0%

cross-domain

前后端分离开发跨域实践

跨域这个问题可谓是老生常谈,在实际工程开发中也有不同的解决办法。本篇文章来总结跨域的原理和我在前后端完全分离开发中,遇到跨域的解决方法。

跨域的原理

跨域条件

跨域是浏览器限制,目的是为了防止不同域之间访问造成安全问题。何为不同域呢?简单理解,既是不同域名下则产生了跨域。详细包括不同的端口、不同协议、不同子域名、不同域名下都算跨域。具体可以见下面的引用表格:

URL 说明 是否跨域
http://www.a.com/a.js, http://www.a.com/b.js 同一域名下
http://www.a.com/lab/a.js, http://www.a.com/script/b.js 同一域名下不同文件夹
http://www.a.com:8000/a.js, http://www.a.com/b.js 同一域名,不同端口
http://www.a.com/a.js, https://www.a.com/b.js 同一域名,不同协议
http://www.a.com/a.js, http://192.22.45.12/b.js 域名和域名解析ip
http://www.a.com/a.js, http://script.a.com/b.js 两个子域名不相同
http://www.a.com/a.js, http://a.com/b.js 主域名和子域名 是(cookie也无法访问)
http://www.cnblogs.com/a.js, http://www.a.com/b.js 不同域名

由于跨域浏览器的限制,所有来源于一个域内的Js请求在请求其他域时,就会被浏览器拦截下。注意这里的拦截下是指在请求回调过程中。

跨域资源共享(Cross-Origin Resource Sharing,简称 CORS)

既然是跨域是浏览器事件,那么浏览器进行跨域资源共享呢。就要利用CORS机制,跨域资源共享标准新增了一组 HTTP 首部字段:

  • 请求头:

Origin 参数表示发起一个针对跨域资源共享的请求的来源

  • 响应头:

Access-Control-Allow-Origin 表示指定哪一类网站可以跨域资源共享

Access-Control-Allow-Methods 表示服务器允许客户端使用POST, GET 和 OPTIONS 方法发起请求

Access-Control-Expose-Headers 头让服务器把允许浏览器访问的头放入白名单

Access-Control-Max-Age 头指定了preflight请求的结果能够被缓存多久

Access-Control-Allow-Credentials 头指定了当浏览器的credentials设置为true时是否允许浏览器读取response的内容

Access-Control-Allow-Headers 首部字段用于预检请求的响应,其指明了实际请求中允许携带的首部字段

当产生跨域时,就可以通过配置HTTP头部字段来防止请求被浏览器拦截的情况。具体只要在服务器的响应中,设置响应头Access-Control-Allow-Origin和请求头Origin匹配,即可通过CORS机制避免跨域问题。也可以通过设置Access-Control-Allow-Origin为*,表示服务器允许来自所有域的请求。

实际问题

Cookie与Session

在许多业务场景中,往往会存在用户登录态需求,这是通过传统的Session来实现的,而对于Session的客户端记录,大部分的B/S架构会存在于Cookie中,通过Cookie中的SessionID来保留客户端Session记录。

在正常的非跨域请求中,Cookie是可以带入请求头的,那么SessionID会隐藏的通过请求带给服务器,服务器通过SessionID判断是否是保持Session会话的客户端。然而在跨域请求中,即使设置了CORS,请求可以相互通信,但是Cookie还是无法通过请求带给服务端,此时Session会话无法保持。

通过尝试将Access-Control-Allow-Credentials设置为True即可将Cookie带入请求。并且在客户端中要将withCredentials参数设置为true。匹配之后才能传递Cookie。

具体在xhr对象中是以withCredentials参数存在,在fetch中是以credentials: ‘include’;参数存在。同时后台的Access-Control-Allow-Credentials设置也要根据不同的后台框架的HTTP头设置进行调整匹配。

推荐CORS插件