YBFACC / blog

仅记录个人学习使用
3 stars 0 forks source link

CORS #14

Open YBFACC opened 4 years ago

YBFACC commented 4 years ago

CORS

跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求

引用来自MDN

我的完整代码

简单请求和复杂请求

两者的区别在于:是否需要发送预检请求。

满足以下条件就可以不需要发送预检请求👇

简单请求测试

使用axios库来简化ajax操作。

发送一个get请求

当我们像平常一样发送 GET 请求时,会出现跨域报错。

1

解决的方法就是加上Access-Control-Allow-Origin:*这个 Header。

2

可以看到我们的跨域请求正常收到了。

其实你可以通过服务端的日志看到,其实服务端是正常返回的。浏览器帮你拦截了这个请求。

带 Cookie 的 GET 请求

axios 需要打开 withCredentials: true (默认为false)

const api = axios.create({
  timeout: 1000,
  withCredentials: true
});

3

可以看到报错了。这里需要我们将Access-Control-Allow-Origin:指定明确的域名。

5

还是报错这里需要我们加上另一个 Header Access-Control-Allow-Credentials 为 true。

80

可以看到请求正常了。

客户端需要获取服务端设置的 Header

你在服务端设置 Header

ctx.res.setHeader('X-Custom-Header',"TestCors")

然后客户端打印下可以拿到的 Header

100

可以看到确实没有拿到我们需要的 Haeder。我们需要指定 Access-Control-Expose-Headers

ctx.res.setHeader('Access-Control-Expose-Headers', 'X-Custom-Header')

客户端再次打印可以拿到的 Header。

1

可以看到我们需要的 Header已经正常了。

复杂请求测试

复杂请求需要在正式请求前加一个 Haeder。

我们可以看看一个服务端的日志。

3

发送了2次请求:一次预检、一次正式请求。

我们发送一个 PUT 请求

我们把客户端和服务端都设置成 PUT。

5

我们需要将 Access-Control-Allow-Methods设置成 PUT。(这里最好返回所有支持的方法,以免多次预检)

1

我们可以在 Network 中看到 OPTIONS 请求。

2

可以看到 PUT 请求请求正常。

减少发送预检的次数

我们可以设置 Access-Control-Max-Age 来设置预检的有效期。

ctx.res.setHeader('Access-Control-Max-Age', '30')

打印服务端的日志👀来看清每次请求

3

当超过设置的时间后,再次请求。可以看到又请求了。

30

客户端需要获取服务端设置的 Header

同上

服务端获取客户端设置的 Header

我们在客户端设置 Header,然后在服务端获取。

const api = axios.create({
  timeout: 1000,
  headers: { 'X-Custom-Header': 'foobar' }
});

我们可以看到报错了。

1

这里我们需要指定 Access-Control-Allow-Headers

ctx.res.setHeader('Access-Control-Allow-Headers', 'X-Custom-Header')
//省略一些代码
ctx.req.headers['x-custom-header']
1

可以看到我们获取了客户端设置的 Header。

关于 Access-Control-Request-Headers

引用MDN来自:请求头 Access-Control-Request-Headers出现于 preflight request(预检请求)中,用于通知服务器在真正的请求中会采用哪些请求头。

没试出作用😰。

关于跨域的误区

  1. ✕ 动态请求就会有跨域的问题

✔ 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境

  1. ✕ 跨域就是请求发不出去了

✔ 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了

引用来自我知道的跨域与安全

参考

HTTP访问控制(CORS)

跨域资源共享 CORS 详解