跨域问题

Youky ... 2021-10-8 浏览器 About 3 min

# 跨域问题

原因浏览器的同源策略。从安全性的角度考虑,为了限制非同源的接口请求和DOM查询。

同源:协议、IP地址、端口号相同的属于同源。

PS:域名和域名对应的IP地址,也属于跨域。

# JSONP

原理:script标签的获取是不受跨域限制的,因此可以通过加载跨域的js来实现跨域。

限制:只能进行get请求。

实现方法:

<script>
    function fn(data){
        // 对于请求的数据的操作
        console.log(data);
    }
</script>
<script src="http://domain.com/api?callback=fn"></script>
1
2
3
4
5
6
7

# CORS

CORS是一个W3C的标准,全称是跨域资源共享,允许浏览器向跨域服务器发送网络请求。

CORS标准将请求分为两类,简单请求非简单请求

CORS请求的响应头,都以Access-Control-开头:

  • Access-Control-Allow-Origin:必选。允许跨域请求的源,要么为请求头中Origin的值,要么为*
  • Access-Control-Allow-Credentials:可选。表示是否允许发送cookie
  • Access-Control-Expose-Headers:可选。允许额外暴露的响应头字段(默认情况下只允许使用Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma六个字段)

# 简单请求

简单请求的定义是:

  1. 请求方法是GET、POST、HEAD中的一种
  2. header中的字段不超过:AcceptAccept-LanguageContent-LanguageContent-Type

对于简单请求,浏览器直接发送CORS请求。并在请求头中添加一个Origin字段,服务器根据这个字段决定是否同意这次请求。

# 非简单请求

对于非简单请求,会在通信前增加一次查询,称为“预检请求”。

预检请求使用的方法是OPTION,并附加三个字段:

  • Origin:发送请求的源
  • Access-Control-Request-Method必选。列出浏览器要用到哪些请求方法
  • Access-Control-Request-Headers可选。列出浏览器要使用的额外的请求头字段

服务器收到预检请求后,根据上述三个字段的值判断是否允许。若确认允许,则返回响应。对于非简单请求特有的是:

  • Access-Control-Allow-Methods:必选。列出允许使用的所有方法,而不只是请求中列出的方法(避免多次预检请求)
  • Access-Control-Allow-Headers:若请求中包含Access-Control-Request-Headers则必选。列出支持的所有头部字段
  • Access-Control-Max-Age:可选。本次预检请求的有效时间

# nginx代理

有两种思路:

  1. 和CORS一样,通过设置Access-Control-系列字段实现跨域。
  2. 通过反向代理。由于服务端的请求不存在跨域问题,以nginx为中转可以将一个跨域的服务代理到同源上

# 中间件跨域

和nginx原理相同,通过代理服务器实现数据转发。

# WebSocket

WebSocket是一种HTML5的新协议,用于实现浏览器和服务器的全双工通信,并且支持跨域

# document.domain + iframe

仅限两个页面的主域相同,子域不同的情况。 eg:http://www.domain.com/a.html和http://child.domain.com/b.html。

原理:两个页面都通过js强制设置document.domain为基础主域(相同的domain.com)

# location.hash + iframe

A域的a页面和B域的b页面之间想要通信,则通过一个A域的c页面。

a和b、b和c之间,都是单向通信,但a和c之间是同域所以可以实现双向通信

# window.name + iframe

window.name属性的特殊之处:在不同的页面加载后仍然存在,且可以支持很长的name值(2MB)

原理:

  • a.html要和b.html通信,引入一个代理页面proxy.html。
  • 在a中,先用iframe加载b,然后再次加载proxy,此时window.name属性仍然存在,且a和proxy同域可以读取

# postMessage

postMessage是HTML5新提供的允许跨域的API,可以实现页面和iframe之间的消息传递

Last update: November 27, 2021 21:16
Contributors: youky7