1. 跨域
1.1 跨域问题来源
跨域问题的来源是浏览器为了请求安全而引入的基于同源策略(Same-origin policy)的安全特性。
同源策略是浏览器一个非常重要的安全策略,基于这个策略可以限制非同源的内容与当前页面进行交互,从而减少页面被攻击的可能性。
当页面和请求的协议、域名或端口不同时,浏览器判定两者不同源,从而产生跨域。需要注意的是跨域是浏览器的限制,实际请求已经正常发出和响应了。
1.2 预检请求
CORS 跨域请求,又分成简单请求 simple request, 和复杂请求 not-so-simple request
- 只有跨域的情况下,才会发生预请求
- 与前述简单请求不同,「需预检的请求」要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。「预检请求」的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。
OPTIONS 请求方法的主要用途有两个
- 获取服务器支持的 HTTP 请求方法;
- 用来检查服务器的性能。例如:AJAX 进行跨域请求时的预检,需要向另外一个域名的资源发送一个 HTTP OPTIONS 请求头,用以判断实际发送的请求是否安全。
什么时候会触发 OPTIONS 请求
- 使用了下面任一 HTTP 方法:
PUTDELETECONNECTOPTIONSTRACEPATCH
- 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:
AcceptAccept-LanguageContent-LanguageContent-Type (but note the additional requirements below)DPRDownlinkSave-DataViewport-WidthWidth
- Content-Type 的值不属于下列之一:
application/x-www-form-urlencodedmultipart/form-datatext/plain
1.3 同源策略
如果两个 URL 的协议、域名和端口都相同,我们就称这两个 URL 同源。
比如下面这两个 URL,它们具有相同的协议 HTTPS、相同的域名,以及相同的端口,所以我们就说这两个 URL 是同源的。
https://time.geekbang.org/?category=1
https://time.geekbang.org/?category=0
浏览器默认两个相同的源之间是可以相互访问资源和操作 DOM 的。
两个不同的源之间若想要相互访问资源或者操作 DOM,那么会有一套基础的安全策略的制约。
为什么会要有同源策略
同源策略是为了保护 Web 安全而存在的。
在 Web 上,不同的网站之间经常需要互相交换数据,如果没有同源策略的限制,就可能会导致一些安全问题
- 例如,一个恶意网站可以通过某种方式,让用户在其他网站上执行一些危险操作,例如盗取用户的信息、发起 CSRF 攻击等等。因此,浏览器引入了同源策略的限制,要求同源的网站之间才能互相交换数据。
- 同源指的是协议、域名、端口号都相同,只有满足这三个条件的网站之间才能互相通信。这样,恶意网站就无法访问其他网站的数据,也无法执行一些危险操作。
1.4 解决方法
- CORS
跨域资源共享(CORS, Cross- Origin Resource Sharing)是浏览器为 AJAX 请求设置的一跨域机制让其可以在服务端允许的情况下进行跨域访问,主要通过 HTTP 响应头来告诉浏览器服务端是否允许当前域的脚本进行跨域访问
原理简述:
允许浏览器向跨域服务器发送请求通过携带一些头部信息询问是否可以跨域,在服务端允许的情况下,服务器端会返回一些头部信息给浏览器,说明允许跨域。
浏览器会在发送跨域请求前,先向服务器发送一个 OPTIONS 请求(预检请求),该请求会包含一些额外的头部信息服务端收到预检请求后,会根据这些额外的头部信息判断该请求是否允许跨域访问,并返回一些额外的头部信息,
告诉浏览器是否允许跨域请求,从而完成跨域请求。
需要注意的是,CORS 只是一种浏览器解决跨域的机制,并不是服务器端的解决方案。在服务端,可以通过一些其他的方法(如:JSONP、代理等)来解决跨域问题。
- 反向代理
跨域是为了突破浏览器的同源策略限制。
既然同源策略只存在于浏览器,那可以换一个思路。
反向代理是代理服务端,为目的服务器收发请求。
当客户端请求访问服务器时,请求首先经过反向代理服务器,然后反向代理服务器将请求发送到内部服务器上进行处理,并将处理结果返回给客户端。
此时,客户端不会知道实际处理请求的内部服务器地址,因为所有请求和响应的交互都通过反向代理进行。
反向代理的情况下客户端不需要做任何操作。
优点:
- 代理服务器可以缓存一些静态资源,提高访问速度。
- 隐藏服务器真实的 IP。
解决原理
- 使用 Nginx 等反向代理服务器作为中间层,将客户端请求转发到内部服务器上进行处理;
- 在反向代理服务器上设置合适的访问控制策略,通过添加 HTTP 头部信息,允许跨域请求。
其他解决方法:JSONP、WebSocket