共计 1890 个字符,预计需要花费 5 分钟才能阅读完成。
关于 http 请求的一些理解:CORS 是一个 w3c 标准,全称为 Cross-origin resoursce sharing(跨域资源共享),它允许浏览器向不用源的服务器发起 XMLHttpRequest 请求,从而可以略过 ajax 同源策略的限制。
简单请求:只要满足请求方法是 HEAD、GET、POST;HTTP 头信息不超出以下字段 Accept Accept-Language Content-Language Last-Event-ID Content-Type: application/x-www-form-urlencode multipart-data text/plain 就属于简单请求。
对于简单请求,基本就是在请求中自动在头信息中添加一个 origin 字段,例如 Origin: http://localhost:8000, 这表示同意 locahost:8000 的请求。如果 origin 指定的源不在许可范围内,服务器会返回一个正常的 HTTP 回应,如果浏览器没有发现 Resonse Headers 响应头信息没有包含 Access-Control-Allow-Origin 就会抛出错误,但这种错误无法通过 status code 来识别,因为返回的状态码可能是 200.
如果你使用的域名是 origin 允许的,Response Headers 里会多出几个基本头信息字段:
Access-Control-Allow-Credential: true,
Access-Control-Allow-Headers:origin, content-type, accept, x-request-with,
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS,
Access-Control-Allow-Origin: http:localhost:8000
Access-Control-Allow-Credential:表示是否允许发送 cookies。默认情况下,Cookies 不包括在 CORS 请求中;设为 true 表示 cookies 可以包含在请求中一起发给服务器,如果不需要发送 cookies 给服务器,需删除字段。需要注意的是:除了设置 Access-Control-Allow-Credential:true 外,在 ajax 请求中也必须打开 withCredentials, 方法如下:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
否则就算服务器同意发送或设置 cookie,浏览器也不会发送或处理。如果不想发送 cookie,最保险的方法就是:
xhr.withCredentials = false;
Access-Control-origin: 必填项,要么是 origin 指定的被允许的值,要么是 *,表示接受任意域名的请求。
非简单请求:非简单请求是那种对服务器有特殊要求的请求,比如 PUT DELETE,或者 Content-Type:application/json 等。非简单请求会在正式通信前增加一次 HTTP 查询请求,成为 flight(预检)。浏览器先询问服务器,当前请求域是否在服务器许可名单中,以及可以使用哪些 HTTP 动词头信息字段,如果返回 true 浏览器会发出 XMLHTTPRequest 请求否则会报错。下面是一个例子:
var url = ‘http://localhost:8000’;
var xhr = new XMLHttpRequest();
xhr.open(‘DELETE’, url, true);
xhr.setRequestHeader(‘x-request-with’, ‘value’);
xhr.send();
这里,HTTP 请求中,方法是 DELETE,并发送了一个头信息为 x -request-with,浏览器发现,这是一个非简单请求,就会自动预检,要求服务器预检这个 HTTP 头信息。
预检请求用的方法是 OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是 origin,表示来源于哪个源。除了 origin,预检还包括 Method Headers,分别为:
Access-Control-Request-Method: DELETE,
Access-Control-request-Headers: x-request-with,
浏览器收到 flight 预检以后检查了 origin Access-Control-Request-Method 和 Access-Control-Request-Headers 字段后确认允许跨域请求,就可以作出回应。