跨域资源请求
# 0.前言
这块知识点挺琐碎的,基本都了解,但是总是有些小点总是记不住。
# 1. CORS 跨域相关
# 1. 如何区分简单请求和复杂请求?
只要同时满足以下两大条件,就属于简单请求:
# Method
HEAD
GET
POST
# Headers
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
2
3
4
5
6
7
8
9
10
11
12
13
14
请对如下请求做出判断:
// 简单请求
fetch("http://crossdoman.com/api/news")
// 请求方法错误
fetch("http://crossdoman.com/api/news",{ method: "PUT" })
// 请求头
fetch("http://crossdoman.com/api/news", {headers: {a:1}})
// 典型场景:当 payload 字段为 json 时,也属于跨域
fetch("http://crossdoman.com/api/news", {
headers: {"content-type":"application/json"},
method: "post",
})
2
3
4
5
6
7
8
9
10
11
12
13
14
# 2.服务端如何处理简单请求的跨域?
【浏览器】默认行为:
在头信息之中,增加一个
Origin
字段GET /cors HTTP/1.1 Origin: http://api.bob.com 【自定添加】 Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
1
2
3
4
5
6
【服务端】行为:
对简单请求的响应
只需要去判断
Origin
是否是指定源,如果成功。Access-Control-Allow-Origin: http://api.bob.com 【通过此属性判断是否成功】 Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
1
2
3
4🚨 注:此错误无法通过状态识别,响应状态码很有可能为
200
,但可被XMLHttpRequest
的onerror
回调函数捕获
# 3. 服务端如何处理复杂请求的跨域?
【浏览器】默认行为:
`OPTIONS` 预检请求 : 同上,默认也会在头信息之中,增加一个`Origin`字段
↓
真实 `AJAX` 请求 (XMLHttpRequest)
2
3
示例脚本:
var url = 'http://api.alice.com/cors'; // ❎ 跨域
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true); // ❎ 请求方法错误
xhr.setRequestHeader('X-Custom-Header', 'value'); // ❎ 请求头错误
xhr.send();
2
3
4
5
【服务端】行为:
对预检请求的响应
除了
Access-Control-Allow-Origin
字段外,还会校验复杂请求额外要求的请求头(Access-Control-Request-Method
) 和方法(Access-Control-Request-Headers
)跨域请求通过,返回:
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com 【请求源】 Access-Control-Allow-Methods: GET, POST, PUT 【请求方法】 Access-Control-Allow-Headers: X-Custom-Header 【请求头】 Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
1
2
3
4
5
6
7
8
9
10
11
12跨域请求不通过,返回
XMLHttpRequest cannot load http://api.alice.com. Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.
1
2此错误可被
XMLHttpRequest
对象的onerror
回调函数捕获。
# 4. 复杂请求响应字段的 Access-Control-Max-Age
的含义?
预检请求后,服务端响应:
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
2
3
4
其中,Access-Control-Max-Age
指定本次预检请求的有效期,单位秒。示例中,1728000
秒(即20
天)
在首次 OPTIONS
请求后,以后每次浏览器的 CORS
复杂请求就会和简单请求类似了,示例如下:
预检请求后,浏览器发送:
PUT /cors HTTP/1.1
Origin: http://api.bob.com 【浏览器自动添加】
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
2
3
4
5
6
7
服务端响应:
Access-Control-Allow-Origin: http://api.bob.com 【必须包含】
Content-Type: text/html; charset=utf-8
2
# 5. 服务端为什么不推荐 Access-Control-Allow-Origin
设置为星号 ?
与 Cookie
有关,对于 Cookie
来说,依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie
也无法读取服务器域名下的Cookie。
因此,如果需要携带 Cookie
一定要指定明确的、与请求网页一致的域名。
# 6. Cookie
的使用方式
ajax
的跨域请求默认不会附带 cookie
,原生 ajax
需如下配置:
对 xhr
的配置:
// xhr
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
2
3
对于 fetch
的配置
// fetch
fetch(url,{ credentials: true });
2
服务端配置:
Access-Control-Allow-Credential: true
Access-Control-Allow-Origin: "明确的域名"
2
# 7. CORS
请求中,JS
如何获取 http
的响应头信息?
对于 CORS
请求时,通过 XMLHttpRequest
对象的 getResponseHeaders()
方法,可以获取:
Cache-Control
Content-Language
Content-Type
Expires
和Last-Modified
Pragma
正常只能访问以上几个响应信息,如果需要访问其余的响应头,需要通过服务端设置
# 浏览器访问的头放入白名单
Access-Control-Expose-Headers: authorization
2
JS
代码:
getResponseHeader('authorization')
# 8. 为啥 Content-Type
支持的类型?
为啥 Content-Type
支持如下值:
application/x-www-form-urlencoded
multipart/form-data
text/plain
原因,兼容表单 form
组件,在 Ajax
技术出现之前,都是使用 form
表单实现的跨域请求。