JavaScript基础之解决跨域方案

    技术2022-07-10  155

    在JavaScript基础中,跨域问题一直都是被常常问到的问题,可是对于前端来说,实际解决前端问题却很少,现在来聊聊跨域问题。

    首先,我们要明白一个问题,什么是跨域?

    当我们在浏览器的地址栏输入如:https://www.baidu.com的时候,这个地址其实包含三部分,https是协议,www.baidu.com是域名,还有一个端口,那么当去请求与你的协议,域名,端口其中一个不一样的地址资源的时候,就会出现跨域问题,这也是我们常说的通源策略。那么如何解决跨域问题呢?

    1、JSONP

    我们在平时写html代码的时候,比如img标签,比如通过script标签,他们的src都是一个地址,而这个地址往往和自己的是不同域,但是却可以访问到其资源,这就是因为浏览器允许标签跨域访问不同域的资源,所以根据这个原理,我们可以通过动态创建script标签的方式去实现跨域请求:

    // 前端代码 <script> let script = document.createElement('script') script.type = 'text/json' document.head.appendChild(script) handleResponse (res) { console.log(res) // 全局函数,返回请求结果 } </script> // 服务端代码 handleResponse ({code: 0, data: {list: []}})

    2、CORS跨域资源共享

    CORS全称跨域资源共享。是一种跨域机制,它使用额外的http请求头,让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。

    CORS请求分为简单请求和非简单请求

    简单请求条件:

    请求方法:head、get、post

    请求Header: Accept、Accept-Language、Content-Language、Content-type(application/x-www-form-urlencoded、multipart/form-data、text/plain)

    只要满足以上俩个条件,均为简单请求,否则为非简单请求。

    CORS请求的身份证验证

    在默认情况下,跨域请求是不会携带cookie的,所以必须要手动设置,将允许携带cookie,如:xhr.withCredentials=true。因为身份验证请求头中携带了cookie,所以Access-Control-Allow-Origin不能设置为*,应该是具体域名,表示允许请求的域。

    CORS请求响应头部设置

    Access-Control-Allow-Origin: <origin> | * Access-Control-Expose-Headers 头让服务器把允许浏览器访问的头放入白名单 Access-Control-Max-Age 头指定了preflight请求的结果能够被缓存多久 Access-Control-Allow-Credentials头指定了当浏览器的credentials设置为true时是否允许浏览器读取response的内容。 Access-Control-Allow-Methods 首部字段用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。 Access-Control-Allow-Headers 首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。

    3、nginx反向代理

    通过nginx配置代理服务器域名,实质上也是和CORS一样的原理,通过设置origin字段。

    // nginx配置 server{ # 监听122端口 listen 122; # 域名是localhost server_name localhost; #凡是localhost:122/api这个样子的,都转发到真正的服务端地址http://www.b.com:122 location ^~ /api { proxy_pass http://www.b.com:122; } }

    4、postMessage

    postMessage()是html5新的API,postMessge解决的问题主要是:

    iframe嵌套页面跨域通信

    本页面和其他页面的通信

    多窗口之间通信

    用法: window.postMessage(data, origin),data是要传递的数据,origin:协议+主机+端口号(也可以是*)

    // a页面 <iframe id="iframe" src="http://www.b.com/b.html" style="display:none;"></iframe> <script> var iframe = document.getElementById('iframe'); iframe.onload = function() { var data = { name: 'jianjian' }; // 向http://www.b.com传送跨域数据 iframe.contentWindow.postMessage(JSON.stringify(data),'http://www.b.com'); }; // 接受http://www.b.com返回数据 window.addEventListener('message', function(e) { alert('data from http://www.b.com---> ' + e.data); }, false); </script> // b页面 <script> // 接收http://www.a.com/a.html的数据 window.addEventListener('message', function(e) { alert('data from http://www.a.com/a.html---> ' + e.data); var data = JSON.parse(e.data); if (data) { data.number = 16; // 处理后再发回http://www.a.com/a.html window.parent.postMessage(JSON.stringify(data), 'http://www.a.com'); } }, false); </script>

    5、WebSocket协议跨域

    WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。 原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。

    <div>user input:<input type="text"></div> <script src="https://cdn.bootcss.com/socket.io/2.2.0/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>

    这些是我们常见的解决跨域的方式,不全,但是一定是最主要的。

    Processed: 0.024, SQL: 9