跨域相关知识点

163 阅读5分钟

什么是同源策略?

比如:1. www.baidu.com:80 -> 2. baidu.com:80

首先 第1个地址 和 第2个地址最大的区别就是 http 协议不同 和 主机名 不同. 同源策略最核心的要点就是 http协议必须完全一致 主机名 必须完全一致 端口号必须完全一致 同源策略是浏览器防止网站数据被篡改的一种机制。

如下图所示:

同源策略.png

如何进行跨域?

CORS

CORS(Cross-Origin Resource Sharing)是一种机制,它允许浏览器向跨源服务器发出资源请求。浏览器通常会在跨源的 HTTP 请求中添加一个 Origin 头,表示请求来自哪个源。服务器如果希望它可以被跨域访问,就可以在响应中添加一个 Access-Control-Allow-Origin 头,表示允许哪个源访问。 CORS的本质就是允许服务器通过设置 HTTP 头来告诉浏览器,哪些域名、协议、端口可以访问资源。如果浏览器发现自己无法访问资源,就会在后台向服务器发送一个预检请求(preflight request),询问服务器是否允许跨域访问。服务器如果允许,就会在响应中添加 Access-Control-Allow-Origin 头,告诉浏览器可以发起正式的跨域请求。

当然这里分为简单请求和复杂请求的.

比如: A 通过响应头告诉浏览器,我愿意共享给 B 这就是一个简单请求

复杂请求就是 浏览器为了防止 POST/PUT/PATCH 请求对数据造成影响

可能复杂请求解释的不是很通俗. 复杂请求就是 比如 你在前端使用 xhr.open('POST', 'https://baidu.com:8888/data') xhr.setRequestHeader('aliyu', '23')

你的网站 aliyu.com 这个主机要访问百度服务器上的/data这个接口的话, 那么在百度服务器后端代码里面就需要设置以下三个

Access-Control-Allow-Origin 设置这个头 对应的 主机 aliyu.com:80。 设置这个的意思就是说 以后 aliyu.com:80 这个地址发送过来的请求都可以访问。

Access-Control-Allow-Methods 这个这个头的意思就是一个 HTTP 头,用于告诉浏览器哪些 HTTP 方法可以跨域访问。

写法:

'Access-Control-Allow-Methods', 'POST, GET, OPTIONS'

当浏览器发现自己无法访问某个资源时,会在后台发送一个预检请求(preflight request)。预检请求的方法是 OPTIONS,它的目的是询问服务器是否允许跨域访问。服务器如果允许,就会在响应中添加 Access-Control-Allow-Methods 头,表示浏览器可以发起哪些方法的跨域请求。 例如,如果服务器允许浏览器发起 GETPOST 请求,就可以返回如下响应:

HTTP/1.1 200 OK
Access-Control-Allow-Methods: GET, POST

浏览器收到这个响应后,就可以发起 GETPOST 请求。如果浏览器想要发起其他方法的请求,比如 DELETEPUT,就会再次发起预检请求,询问服务器是否允许跨域访问。

注意,Access-Control-Allow-Methods 头只能在响应预检请求时使用。正式的跨域请求(比如 GETPOST)不会携带这个头。

JSONP

JSONP(JSON with Padding)是一种在浏览器端跨域访问资源的技术。通过动态插入一个 <script> 标签的方式,实现跨域访问。

在使用 JSONP 的情况下,浏览器会向服务器发送一个带有回调函数名的请求,例如:

GET https://baidu.com/resource?callback=foo

服务器收到请求后,会返回一个带有回调函数调用的 JSON 格式的响应,例如:

foo({ "aliyu": "23" });

浏览器会解析这个响应,并调用名为 foo 的回调函数,传入解析后的 JSON 对象。

由于 JSONP 使用的是动态插入的 <script> 标签,所以它不受浏览器的同源策略限制。但是,由于它是通过动态插入的方式实现跨域访问,所以它只能用于发起 GET 请求,不能用于发起其他类型的请求(比如 POSTDELETE 等)。

JSONP 已经被 CORS 取代.

反向代理(Nginx)之跨域
  1. 在反向代理服务器上设置跨域访问策略。反向代理服务器需要添加 Access-Control-Allow-Origin 头,表示允许浏览器访问指定的域名。或者向代理服务器添加 proxy_pass 例如:
//允许 http://a.com:8888 访问
假设你的网站是b.com 那么你就必须在代理服务器去后端发送请求访问 a.com 这样就是服务器去请求 请求到数据后返回给b.com你自己. 然后前端就可以直接访问 b.com/data 拿到数据了

location /data {
    proxy_pass http://a.com:8888;
}

//允许任意 域名 或者 ip 访问
location / {
    proxy_set_header Access-Control-Allow-Origin *;
}

  1. 在前端中,使用反向代理服务器的地址发起跨域请求。例如:
fetch('http://b.com/data')
    .then(response => response.json())
    .then(data => console.log(data));

这样,浏览器会向反向代理服务器发起请求,反向代理服务器再将请求转发到目标服务器。由于反向代理服务器已经设置了跨域访问策略,所以浏览器就可以正常地访问目标服务器了。

注意,反向代理服务器只能用于解决前端跨域访问的问题。如果服务器端的 API 需要跨域访问,就需要在服务器端设置跨域访问策略,比如使用 CORS。