跨域问题常见的3中解决方案

2,459 阅读4分钟

前言

跨域问题,已困扰面试者久已。今天,就把它安排的明明白白的。

什么是跨域

首先得知道什么是跨域,为什么会有跨域这个问题。

原因是:浏览器的同源策略

原因总结:

出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。 (译者注:这段描述不准确,并不一定是浏览器限制了发起跨站请求,也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。)

上面一段话摘录于MDN,但不太准确,我个人认为:跨域的问题,不是浏览器拦截了请求的发送,而是浏览器拦截了请求的响应

触发跨域的判断条件

只要出现下面的任一情况,就算不同源(即跨域)

  1. 协议不同(例如:http和https)
  2. 端口不同
  3. 域名不同(例如:a.baidu.com和b.baidu.com)

tips:在我们日常开发的时候,本地前端项目起了一个8080端口的服务,然后又起一个3000端口的后端项目服务。这个时候,就跨域了(端口不一致)

怎么解决跨域呢

老生常谈的jsonp(前端+后端)

应该没人在用这个方式去解决跨域问题了,但不排除可能出现适合使用jsonp的场景。

前端构造script标签请求指定URL(由script标签发出的GET请求不受同源策略限制),服务器返回一个函数 执行语句,该函数名称通常由查询参callback的值决定,函数的参数为服务器返回的json数据。该函数在前 端执行后即可获取数据。

代理服务器(前端或者nginx)

请求同源服务器,通过该服务器转发请求至目标服务器,得到结果再转发给前端。

前端开发中测试服务器的代理功能就是采用的该解决方案,但是最终发布上线时如果web应用和接口服务器 不在一起仍会跨域。

CORS(Cross Origin Resource Share) - 跨域资源共享(后端)

后端只需要在响应报文中设置一个请求头即可:

image.png
(图片来自MDN)

如上图的例子:

  1. 客户端发起请求的时候带上了Origin: Server-b.com
  2. 服务端响应的时候返回了Access-Control-Allow-Origin: *

使用 OriginAccess-Control-Allow-Origin 就能完成最简单的访问控制。

本例中,服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问。

假如只想被http://foo.example访问,则可以这么设置:Access-Control-Allow-Origin: http://foo.example

Proxy代理模式

处理跨域的时候,还有一个比较重要的方式:代理

原理是:

  1. 跨域是在浏览器才会发生的,在服务器端是不存在这个概念的。

  2. 浏览器发送请求时,还是按正常的请求发送,例如:

    1. http://foo.example网页要请求http://hotao.example/api/user接口。(直接按详细的url请求会跨域)
    2. http://foo.example网页发出http://foo.example/api/user的请求
  3. 然后,在本地服务器(比如webpack启动的node服务器)对接口做一次拦截,如果是/api/所匹配的,则把这个接口转发到目标地址http://hotao.example/api/user中。

  4. 这样,浏览器发送请求和接收请求时,都是同一个源。而转发的操作在node服务器上完成的。所以,不会触发跨域。

具体案例

vue-cli的项目中,可以为开发环境做代理配置:

image.png

上述配置中,端口5678且请求地址匹配/api/则代理到http://localhost:4000

例如:请求http://localhost:5678/api/userList将会被代理到http://localhost:4000/api/userList

nginx中的代理配置

image.png

nginx中的原理和vue-cli的也是比较类似。稍微做一点配置即可。

图中的配置,将会把80端口的/api请求代理到http://127.0.0.1:4000服务器上。 例如:http://www.hotao.work/api/userList会被代理到http://127.0.0.1:4000/api/userLis

跨域的问题就到这里了。

后记

实际工作中,经常会遇到请求发送两遍:

  1. options请求
  2. 原请求

为什么会出现这个情况呢?

这与cors的预检请求有关,相关资料在MDN上有详细解释,有兴趣可以了解一下。