Open YBFACC opened 4 years ago
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
引用来自MDN
我的完整代码
两者的区别在于:是否需要发送预检请求。
满足以下条件就可以不需要发送预检请求👇
使用axios库来简化ajax操作。
当我们像平常一样发送 GET 请求时,会出现跨域报错。
解决的方法就是加上Access-Control-Allow-Origin:*这个 Header。
Access-Control-Allow-Origin:*
可以看到我们的跨域请求正常收到了。
其实你可以通过服务端的日志看到,其实服务端是正常返回的。浏览器帮你拦截了这个请求。
axios 需要打开 withCredentials: true (默认为false)
const api = axios.create({ timeout: 1000, withCredentials: true });
可以看到报错了。这里需要我们将Access-Control-Allow-Origin:指定明确的域名。
Access-Control-Allow-Origin:
还是报错这里需要我们加上另一个 Header Access-Control-Allow-Credentials 为 true。
Access-Control-Allow-Credentials
可以看到请求正常了。
你在服务端设置 Header
ctx.res.setHeader('X-Custom-Header',"TestCors")
然后客户端打印下可以拿到的 Header
可以看到确实没有拿到我们需要的 Haeder。我们需要指定 Access-Control-Expose-Headers。
Access-Control-Expose-Headers
ctx.res.setHeader('Access-Control-Expose-Headers', 'X-Custom-Header')
客户端再次打印可以拿到的 Header。
可以看到我们需要的 Header已经正常了。
复杂请求需要在正式请求前加一个 Haeder。
我们可以看看一个服务端的日志。
发送了2次请求:一次预检、一次正式请求。
我们把客户端和服务端都设置成 PUT。
我们需要将 Access-Control-Allow-Methods设置成 PUT。(这里最好返回所有支持的方法,以免多次预检)
Access-Control-Allow-Methods
PUT
我们可以在 Network 中看到 OPTIONS 请求。
可以看到 PUT 请求请求正常。
我们可以设置 Access-Control-Max-Age 来设置预检的有效期。
Access-Control-Max-Age
ctx.res.setHeader('Access-Control-Max-Age', '30')
打印服务端的日志👀来看清每次请求
当超过设置的时间后,再次请求。可以看到又请求了。
同上
我们在客户端设置 Header,然后在服务端获取。
const api = axios.create({ timeout: 1000, headers: { 'X-Custom-Header': 'foobar' } });
我们可以看到报错了。
这里我们需要指定 Access-Control-Allow-Headers
Access-Control-Allow-Headers
ctx.res.setHeader('Access-Control-Allow-Headers', 'X-Custom-Header') //省略一些代码 ctx.req.headers['x-custom-header']
可以看到我们获取了客户端设置的 Header。
引用MDN来自:请求头 Access-Control-Request-Headers出现于 preflight request(预检请求)中,用于通知服务器在真正的请求中会采用哪些请求头。
Access-Control-Request-Headers
没试出作用😰。
✔ 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境
✔ 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了
引用来自我知道的跨域与安全
HTTP访问控制(CORS)
跨域资源共享 CORS 详解
CORS
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
引用来自MDN
我的完整代码
简单请求和复杂请求
两者的区别在于:是否需要发送预检请求。
满足以下条件就可以不需要发送预检请求👇
简单请求测试
使用axios库来简化ajax操作。
发送一个get请求
当我们像平常一样发送 GET 请求时,会出现跨域报错。
解决的方法就是加上
Access-Control-Allow-Origin:*
这个 Header。可以看到我们的跨域请求正常收到了。
其实你可以通过服务端的日志看到,其实服务端是正常返回的。浏览器帮你拦截了这个请求。
带 Cookie 的 GET 请求
axios 需要打开 withCredentials: true (默认为false)
可以看到报错了。这里需要我们将
Access-Control-Allow-Origin:
指定明确的域名。还是报错这里需要我们加上另一个 Header
Access-Control-Allow-Credentials
为 true。可以看到请求正常了。
客户端需要获取服务端设置的 Header
你在服务端设置 Header
然后客户端打印下可以拿到的 Header
可以看到确实没有拿到我们需要的 Haeder。我们需要指定
Access-Control-Expose-Headers
。客户端再次打印可以拿到的 Header。
可以看到我们需要的 Header已经正常了。
复杂请求测试
复杂请求需要在正式请求前加一个 Haeder。
我们可以看看一个服务端的日志。
发送了2次请求:一次预检、一次正式请求。
我们发送一个 PUT 请求
我们把客户端和服务端都设置成 PUT。
我们需要将
Access-Control-Allow-Methods
设置成PUT
。(这里最好返回所有支持的方法,以免多次预检)我们可以在 Network 中看到 OPTIONS 请求。
可以看到 PUT 请求请求正常。
减少发送预检的次数
我们可以设置
Access-Control-Max-Age
来设置预检的有效期。打印服务端的日志👀来看清每次请求
当超过设置的时间后,再次请求。可以看到又请求了。
客户端需要获取服务端设置的 Header
同上
服务端获取客户端设置的 Header
我们在客户端设置 Header,然后在服务端获取。
我们可以看到报错了。
这里我们需要指定
Access-Control-Allow-Headers
可以看到我们获取了客户端设置的 Header。
关于 Access-Control-Request-Headers
引用MDN来自:请求头
Access-Control-Request-Headers
出现于 preflight request(预检请求)中,用于通知服务器在真正的请求中会采用哪些请求头。没试出作用😰。
关于跨域的误区
✔ 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境
✔ 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了
引用来自我知道的跨域与安全
参考
HTTP访问控制(CORS)
跨域资源共享 CORS 详解