Open findxc opened 3 years ago
跨域资源共享,也就是 CORS,全称是 Cross-Origin Resource Sharing 。配置跨域资源共享其实就是配置一些请求头来实现的。
弄了一个有前端代码和后端代码的仓库来在本地进行各种测试,见 https://github.com/findxc/frontend-and-backend-playground 。
backend 路径下有两个文件,一个是没考虑 cookie 的跨域相关设置,一个是有考虑 cookie 的跨域相关设置。
通过 npm run start-no-cookie 或者 npm run start-need-cookie 来启动不同的前后端服务。
npm run start-no-cookie
npm run start-need-cookie
需要注意现在启动的前后端服务都在 localhost 这个域名下,只是端口号不一样,所以暂时 cookie 相关没有涉及到 samesite 这个问题(samesite 默认值是 lax ,而 cross-site 请求需要设为 none 后 cookie 才能使用),但是实际环境中是需要处理 samesite 问题的,因为前后端一般会在不同域名下。
这里也是涉及到一个点,origin 和 site 的区别,两个地址如果协议或者端口号不同,会认为是不同的 origin ,但是对于 site 来说并不关心协议和端口号。
也就是跨 origin 不一样是跨 site 。
前端从地址 a 去请求地址 b 的资源,如果两个地址的协议、域名和端口号都一样,就认为是同域,否则就是跨域。
一些公共的服务端资源,比如 https://unpkg.com/axios@0.21.1/dist/axios.min.js 这种,任意一个前端源都有可能会去请求这个资源。
再比如一些第三方服务,比如高德地图 api ,你去请求的时候肯定是跨域了。
参见 Simple requests 。
一些非简单请求的举例:
application/json
当跨域时,浏览器会自行判断一个请求是不是简单请求。
非简单请求浏览器会先发一个 OPTIONS 请求,并在请求头中携带一些实际请求的信息。然后服务端在响应头中返回允许跨域访问的一些条件。浏览器判断前端实际请求满足跨域条件时才会接着发送实际请求。
当请求另外一个域的资源时,浏览器发送的请求默认是不会携带那个域的 cookie 的,服务端执行 set-cookie 操作不会报错但是实际是无效的。
只有当前端发送请求时设置了 withCredentials 为 true 并且后端响应头中设置了 Access-Control-Allow-Credentials 为 true ,跨域请求才会携带服务端域的 cookie ,服务端 set-cookie 才能成功设置上。
跨域相关的请求头就是以上这些了,本地多测测就理解了。
这里解决的方法 是后端 自定义 http header,对吧
@GrammyLi 如果只是想允许跨域,可以让运维在 nginx 那里配一下 header ,如果说某个接口想暴露额外 header 给前端,一般是后端再额外处理,如果比较通用的也可以配在 nginx 。我是这样理解的,没实战过 -.-
@GrammyLi 我又想了下,我经历过的项目好像都直接后端配的。
跨域资源共享,也就是 CORS,全称是 Cross-Origin Resource Sharing 。配置跨域资源共享其实就是配置一些请求头来实现的。
本地测试环境搭建
弄了一个有前端代码和后端代码的仓库来在本地进行各种测试,见 https://github.com/findxc/frontend-and-backend-playground 。
backend 路径下有两个文件,一个是没考虑 cookie 的跨域相关设置,一个是有考虑 cookie 的跨域相关设置。
通过
npm run start-no-cookie
或者npm run start-need-cookie
来启动不同的前后端服务。需要注意现在启动的前后端服务都在 localhost 这个域名下,只是端口号不一样,所以暂时 cookie 相关没有涉及到 samesite 这个问题(samesite 默认值是 lax ,而 cross-site 请求需要设为 none 后 cookie 才能使用),但是实际环境中是需要处理 samesite 问题的,因为前后端一般会在不同域名下。
这里也是涉及到一个点,origin 和 site 的区别,两个地址如果协议或者端口号不同,会认为是不同的 origin ,但是对于 site 来说并不关心协议和端口号。
也就是跨 origin 不一样是跨 site 。
一些前置知识
什么是跨域
前端从地址 a 去请求地址 b 的资源,如果两个地址的协议、域名和端口号都一样,就认为是同域,否则就是跨域。
为什么要请求跨域资源
一些公共的服务端资源,比如 https://unpkg.com/axios@0.21.1/dist/axios.min.js 这种,任意一个前端源都有可能会去请求这个资源。
再比如一些第三方服务,比如高德地图 api ,你去请求的时候肯定是跨域了。
什么是简单请求
参见 Simple requests 。
一些非简单请求的举例:
application/json
的请求;当跨域时,浏览器会自行判断一个请求是不是简单请求。
非简单请求浏览器会先发一个 OPTIONS 请求,并在请求头中携带一些实际请求的信息。然后服务端在响应头中返回允许跨域访问的一些条件。浏览器判断前端实际请求满足跨域条件时才会接着发送实际请求。
前端发请求时设置 withCredentials 是用来干啥的
当请求另外一个域的资源时,浏览器发送的请求默认是不会携带那个域的 cookie 的,服务端执行 set-cookie 操作不会报错但是实际是无效的。
只有当前端发送请求时设置了 withCredentials 为 true 并且后端响应头中设置了 Access-Control-Allow-Credentials 为 true ,跨域请求才会携带服务端域的 cookie ,服务端 set-cookie 才能成功设置上。
相关 HTTP header 解释
所有请求,包括 OPTIONS 请求都需要设置的响应头
只用 OPTIONS 请求需要设置的响应头
OPTIONS 请求头浏览器自动加上的
当服务端希望暴露某个自定义 header 给前端时
跨域相关的请求头就是以上这些了,本地多测测就理解了。