跨域资源请求
# 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-81
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/plain1
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-ControlContent-LanguageContent-TypeExpires和Last-ModifiedPragma
正常只能访问以上几个响应信息,如果需要访问其余的响应头,需要通过服务端设置
# 浏览器访问的头放入白名单
Access-Control-Expose-Headers: authorization
2
JS 代码:
getResponseHeader('authorization')
# 8. 为啥 Content-Type 支持的类型?
为啥 Content-Type 支持如下值:
application/x-www-form-urlencodedmultipart/form-datatext/plain
原因,兼容表单 form 组件,在 Ajax 技术出现之前,都是使用 form 表单实现的跨域请求。