跨域以及解决方案

理解跨域

不同源地址之间的请求称之为跨域请求(跨源)

所谓同源就是同域名、同协议、同端口,只有同源的地址才可以相互通过ajax方式请求

 btn.onclick = function(){
    let xhr = new XMLHttpRequest;
    // xhr.open('get','http://localhost:2019');//非跨域
    xhr.open('get','http://www.baidu.com');//跨域
    xhr.onload = function(){
        document.write(xhr.responseText)
    }
    xhr.send();
   }

控制台出现 Access-Control-Allow-Origin,就说明已经跨域了

是什么导致了跨域的产生,就会说到浏览器的一种安全机制 —— 同源策略

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响

同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性

同源策略限制以下几种行为:

1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送

解决跨域的方案:

1、CORS

CORS是一个W3C标准,全称是"跨域资源共享"
浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉
因此实现CORS通信的关键是服务器,只要服务器实现了CORS接口,就可以跨源通信
高版本的XMLHttpRequest + 服务器权限解决跨域问题
 
  // 处理成功失败返回格式的工具
    const {successBody} = require('../utli')
    class CrossDomain {
      static async cors (ctx) {
        const query = ctx.request.query
        // *时cookie不会在http请求中带上
        ctx.set('Access-Control-Allow-Origin', '*')
        ctx.cookies.set('tokenId', '2')
        ctx.body = successBody({msg: query.msg}, 'success')
      }
    }
    module.exports = CrossDomain

前台只需要正常发送请求

   fetch(`http://localhost:9871/api/cors?msg=helloCors`).then(res => {
      console.log(res)
    })
 
2、JSONP(json+padding)
script标签中的src能够直接跨域访问资源,并且尽量解析js代码
jsonp必须具备以下条件:
1)保证全局有个函数
2)数据必须是这个函数的调用格式
3)当要请求数据时候,创建一个script标签,把scr等于请求的接口,再把script标签插入到页面,这个时候就做到了按需请求
 
 function fn(data){
      let html = '';
      data.s.forEach(e=>{
        html += `<li>${e}</li>`
      })
      box.innerHTML = html;
      console.log(data)
    }
    txt.onkeyup = function(){
      let jk = document.createElement('script');
      jk.src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd="+this.value+'&cb=fn'
      document.getElementsByTagName('head')[0].appendChild(jk);
    }

jquery的jsonp

   txt.onkeyup = function(){
        $.ajax({
            url:'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?cb=?',
            data:{
                wd:$(this).val()
            },
            dataType:'jsonp',
            success(data){
                let html = '';
                data.s.forEach(e=>{
                    html += `<li>${e}</li>`;
                });
                ul.innerHTML = html;
            }
        });
    }
 
3、服务器代理
通过服务器的文件能访问第三方资源,这个服务器文件又和当前请求的页面同源
这个时候,当前请求的页面去访问服务器文件,就等同于直接请求第三方资源
 
4、WebSocket协议跨域
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信
同时允许跨域通讯,是server push技术的一种很好的实现
 
前台代码
<div>user input:<input type="text"></div>
<script src="./socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');

// 连接成功处理
socket.on('connect', function() {
    // 监听服务端消息
    socket.on('message', function(msg) {
        console.log('data from server: ---> ' + msg); 
    });

    // 监听服务端关闭
    socket.on('disconnect', function() { 
        console.log('Server socket has closed.'); 
    });
});

document.getElementsByTagName('input')[0].onblur = function() {
    socket.send(this.value);
};
</script>

后台代码

var http = require('http');
var socket = require('socket.io');

// 启http服务
var server = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-type': 'text/html'
    });
    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

// 监听socket连接
socket.listen(server).on('connection', function(client) {
    // 接收信息
    client.on('message', function(msg) {
        client.send('hello:' + msg);
        console.log('data from client: ---> ' + msg);
    });

    // 断开处理
    client.on('disconnect', function() {
        console.log('Client socket has closed.'); 
    });
});
 
原文地址:https://www.cnblogs.com/theblogs/p/10614131.html