意外碰到了浏览器自发options请求问题,从懵逼到通,仅以此文来对自己的探索做个总结,同时配以另外一个深度篇讲述跨域遇到的问题和解决方式
发起options的理由-Cors
跨域方式: jsonp, ajax, cors 发展不再赘述,重点看cors的运行机制
Cors原理阐述:cors是结合浏览器和服务器存在的一种跨域机制,分为简单请求和复杂请求
当请求不再是简单请求的时候,浏览器会自发options请求,与服务器通信,带回是否可以跨域的信息,由此开启正 式调用接口。options请求是浏览器自发进行的,用户并不知觉。
服务端的请求方式
请求方式 | 描述 | 应用场景 |
---|---|---|
Get | 请求页面,并返回页面内容 | 获取数据,参数一般设置为params |
Post | 大多数用于提交表单或者文件,数据放在请求体中 | 提交数据,参数一般设置为data |
Options | 预检请求,用于查看服务端性能以及是否可以跨域请求 | 预检索(本文重点) |
Head | 类似于Get请求,只不过返回的响应中没有具体内容,用于获取报头 | 不常用 |
Put | 从客户端向服务器发送的数据取代定制文档的内容 | 不常用 |
Delete | 请求服务端删除指定的页面 | 不常用 |
Connect | 把服务器当做跳板,代替客户端去访问其他网页 | 不常用 |
Trace | 回显服务器收到的服务器收到的请求,用于测试或诊断 | 不常用 |
Cors
请求类型 | 方式 | content-type |
简单请求 | Get,Head,Post | application/x-www-form-urlencoded multipart/form-data text/xml |
复杂请求(需预检) | Options,Put,Delete,Connect,Trace | 非以上三种格式 |
content-type内涵
本质解析:
content-type是Http的实体首部字段,用于表明请求或返回的消息主体是何种格式编码,存在于request-header和response- header
类型解析:
1: application/x-www-form-urlencoded
浏览器的原生form表单,并且提交的数据按照key1=val1& key2=val2....的方式,同时进行了url转码
2: multipart/form-data
常见的post提交数据的方式,并且在form表单里配置属性enctype=“multipart/form-data”
3: text/xml
是一种以Http作为传输协议,XML作为编码规范的远程调用模式
4: application/json
现在常用的json格式规范
跨域过程
跨域请求
发起请求的时候浏览器会自动判断是否为简单请求,如果为简单请求,浏览器直接发出cors请求,实际操作则是在发送信息内自动 添加origin字段,表示当前发起请求的源(协议+域名+端口)
GET /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
PS:User-Agentl: 设备识别信息
服务端响应,返回情况如下
- 服务端拒绝
服务端仍会返回一个正常的状态码,有可能为200,但是头部信息不存在Access-Control-Allow-Origin字段。此时浏览器感应到收到了服务端的拒绝信息, 从而抛出一个错误,被XMLHttpRequest的onerror的回调函数捕获
- 服务端表示同意
如果origin指定的域名在许可范围内,则会在响应的头部信息内添加以下字段Access-Control-Allow-Origin: [http://api.bob.com](http://api.bob.com/) Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
- Access-Control-Allow-Origin 字段
字段必选。 表示服务端允许跨域访问的源,或者指定,或者为‘*’,表示全部通过
- Access-Contaol-Allow-Credentials
字段可选。表示服务端允许该源携带cookie。cookie可以放在请求头中,也可以放在请求体中,服务端设置该属性为false,则明确表示不允许在头部携带。
3: Access-Control-Expose-Headers
字段可选。浏览器在服务端的响应中,通过XMLHttpRequest对象只能获取到6个固定的字段( Cache-Control
、Content-Language
、Content-Type
,Expires
、Last-Modified
、Pragma
)如果需要获取到其他字段的信息,必须在该属性内指定。如上图,指定需要获取FootBar字段内容。
PS: 当请求头部需要携带cookie,设置withCredentials或include:true时,服务端返回的Access-Control-Allow-Origin不能再为‘*’,必须是请求头发出的Oringin
预检请求
预检请求会在正常的cors请求之前,发送预检请求,得到服务端对于跨域是否同意的回应,如果服务端同意,则开始正常的cors请求发送。
预检请求头部信息:
OPTIONS /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-HeaderHost: api.alice.com
Accept-Language: en-USConnection: keep-alive
User-Agent: Mozilla/5.0...
所发送的字段:
Access-Control-Request-Method: 指定请求方式
Access-Control-Request-Headers: 指定头部携带的参数字段信息
Origin:指定源(协议+域名+端口)
服务端返回
PUT /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
服务端收到预检请求后,检查字段信息,后予以返回
字段解释与简单请求一样,不再赘述。
预检请求后
之后,浏览器每次调接口的方式为简单请求方式,每次携带origin,并且每次收到服务端的Access-Control-Allow-Origin,根据返回的状态码进行判断以及取用信息.