duyue6002 / Blog

:pencil2: Write here
http://duyue6002.github.io/Blog/#/
5 stars 1 forks source link

[总结]跨域 #20

Open duyue6002 opened 5 years ago

duyue6002 commented 5 years ago

跨域的重要概念

  1. 同源:同协议、同域、同端口
  2. 限制:Ajax无法发送;无法获取DOM;无法获取cookie/localStorage/indexDB
  3. 不受跨域限制的元素:WebSocket,script、img、iframe、video、audio标签的src属性等
  4. 方法:proxy;cors;jsonp
duyue6002 commented 5 years ago

编程实现

客户端端口:8085,服务端端口:3000

Proxy

   // 访问服务端的 http://127.0.0.1:3000/info/normal
   // 客户端的后端
   router.get('*', (req, res, next) => {
     let path = req.path.replate(/^\/proxy/, '');
     req.get(`http://127.0.0.1:3000${path}`, (err, response) => {
       res.json(JSON.parse(response.body));
     })
   });
   // 客户端的前端
   document.getElementById('btn').addEventListener('click', () => {
     let xhr = new XMLHttpRequest();
     xhr.onreadystatechange = () => {
       if (xhr.readyState === 4 && xhr.status === 200) {
         alert(xhr.responseText);
       }
     }
     xhr.open('get', '/proxy/info/normal');
     xhr.send(null);
   })

优点:无需服务器端改造。 缺点:客户端需要有自己的后端服务;特殊请求头(cookie)在转发时要特殊处理。

CORS

   // 访问服务器的http://127.0.0.1:3000/info/cors
   // 服务端改写
   route.get('/cors', (req, res, next) => {
     res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8085'); // 设置接受域
     res.setHeader('Access-Control-Allow-Credentials', true);   // 可以传cookie
     res.json(data);
   })
   // 客户端改写
   document.getElementById('btn').addEventListener('click', () => {
     let xhr = new XMLHttpRequest();
     xhr.withCredentials = true;
     xhr.onreadystatechange = () => {
       if (xhr.readyState === 4 && xhr.status === 200) {
         alert(xhr.responseText);
       }
     }
     xhr.open('get', 'http://127.0.0.1:3000/info/cors');
     xhr.send(null);
   })

优点:支持各种类型请求(get / post / put等) 缺点:服务器接口需要改造;兼容性不好(IE10以上)

jsonp

利用script不受跨域请求限制的特点,服务器把客户端需要的数据写到js脚本文件返回给客户的,有点类似于CDN。

     // 访问服务端的http://127.0.0.1:3000/info/jsonp
     // 客户端
     function myCallback(res) {
       alert(JSON.stringify(res, null, 2));
     }
     document.getElementById('btn').addEventListener('click', () => {
       let script = document.createElement('script');
       script.src = 'http:127.0.0.1:3000/info/jsonp?cb=myCallback';
       document.getElementByTagName('head')[0].appendChild(script);
     });
     // 或用Ajax
     $.ajax({
       url: 'http:127.0.0.1:3000/info/jsonp?cb=myCallback',
       dataType: 'jsonp',
       jsonp: 'cb',
     }).done((res) => {
       alert(JSON.stringify(res, null, 2));
     })
     // 服务端
     router.get('/josnp', (req, res, next) => {
       let str = JSON.stringify(data);
       let script = `${req.query.cb}(${str})`;
       res.send(script);
     })

优点:兼容性好 缺点:只支持get请求;服务端需要改造