了解前端跨域的一些问题

508 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前端经常会遇到跨域的问题,今天学习并总结一下。

什么是跨域?

浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。如

            http://localhost:8080/web

http是协议;localhost是域名;8080是端口号。也就是说,这三个参数只要有一个不同,就会出现跨域问题。提到跨域问题就得先提到浏览器的同源策略。它是一种约定,是浏览器最核心也最基本的安全功能。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响,可以说Web是构建在同源策略基础之上的。下面给几个例子帮助理解:

满足同源策略,不跨域

    -  浏览器地址 http://localhost:8090/
       请求地址 http://localhost:8090/             //协议、域名、端口都相同
    -  浏览器地址 http://10.0.1.1:80/
       请求地址 http://10.0.1.1/                   //协议、域名、端口都相同(http默认端口80)
    -  浏览器地址 https://10.0.1.1/
       请求地址 https://10.0.1.1:443/              //协议、域名、端口都相同(https默认端口443)

不满足同源策略,跨域

    -  浏览器地址 http://localhost:8090/
       请求地址 http://localhost:8091/         //协议、域名相同,端口不同
    -  浏览器地址 http://localhost:8090
       请求地址 https://localhost:8090             //域名、端口相同,协议不同

浏览器为了安全问题一般都限制了跨域访问,不允许跨域请求资源。

解决跨域问题的方法总结

1. 主域相同子域不同之document.domain跨域

  • 主域名由两个或两个以上的字母构成,中间由点号隔开,整个域名通常只有1个点号。 百度的主域名是baidu.com。
  • 子域是在主域名之下的域名,域名内容会有多个点号,如 www.baidu.com 浏览器是通过document.domain属性来检查两个页面是否同源,因此只要通过设置相同的document.domain,两个页面就可以共享Cookie。由于document.domain的修改是有限制的,只能设置为自身或者更高一级的域名,且主域要相同,此方案仅限主域相同,子域不同的跨域应用场景。

如域名是 www.test.com  可以给document.doamin赋值。但是,只能给当前域名或者它的基础域名赋值,才有效。

        document.domain = 'test.com';            // 两个页面都设置

2. JSONP

利用script标签的src和img标签的src,或者说link标签的href它们没有被同源策略所限制,没有跨域限制。当需要通讯时,本站脚本创建一个script元素,利用script标签来执行跨域的javascript代码。通过这些代码,我们就能实现前端跨域请求数据(GET请求)。第三方产生的响应为json数据的包装(故称之为jsonp,即json padding)。

要提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。为什么要定义callback呢?首先我们知道,这个get请求已经被发出去了,那么我们如何接口请求回来的数据呢,callback则可以帮我们做这件事。

jsonp的整个过程就类似于前端声明好一个函数,后端返回执行函数。执行函数参数中携带所需的数据。

JSONP的缺点:

  • 具有局限性, 仅支持get方法
  • 不安全,可能会遭受XSS攻击

3. CORS

CORS -- 跨站资源共享,它是跨域的官方解决方案,升级版的JSONP。普通跨域请求:只需服务器端设置Access-Control-Allow-Origin带cookie跨域请求:前后端都需要进行设置。根据xhr.withCredentials字段判断前端是否带有cookie。服务器端对于CORS的支持,主要是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。

4. Nginx

nginx代理跨域,实质和CORS跨域原理一样,通过配置文件设置请求响应头Access-Control-Allow-Origin…等字段。

代理跨域。反向代理跨域。实现原理类似于 Node 中间件代理,需要你搭建一个中转 nginx 服务器,用于转发请求。使用 nginx 反向代理实现跨域,是最简单的跨域方式。只需要修改 nginx 的配置即可解决跨域问题,支持所有浏览器,支持 session,不需要修改任何代码,并且不会影响服务器性能。

5. webpack本地代理

在webpack.config.js中利用 WebpackDevServer 配置本地代理,详情配置 devServer

6. websocket

是 HTML5 的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。