轉載 http://stylechen.com/options-cors.html?utm_source=tuicool&utm_medium=referral
OPTIONS 方法在跨域請求(CORS)中的應用
OPTIONS 方法比較少見,該方法用於請求服務器告知其支持哪些其他的功能和方法。通過 OPTIONS 方法,可以詢問服務器具體支持哪些方法,或者服務器會使用什么樣的方法來處理一些特殊資源。可以說這是一個探測性的方法,客戶端通過該方法可以在不訪問服務器上實際資源的情況下就知道處理該資源的最優方式。
既然比較少見,什么情況下會使用這個方法呢?
最近在做跨域文件上傳的時候,瀏覽器會自動發起一個 OPTIONS 方法到服務器。
如果只是普通的 ajax 請求,也不會發起這個請求,只有當 ajax 請求綁定了 upload 的事件並且跨域的時候,就會自動發起這個請求。
var xhr = new XMLHttpRequest(); var url = 'http://api.xxx.com/upload'; xhr.open('POST', url); xhr.upload.addEventListener('progress', function (){ // ... }, false); xhr.upload.addEventListener('load', function (){ // ... }, false); xhr.upload.addEventListener('error', function (){ // ... }, false); xhr.upload.addEventListener('abort',function (){ // ... }, false); xhr.send(data);
上面的代碼是在 xxx.com 域下發起了一個跨域的 POST 請求,期望提交數據到 api.xxx.com 這個域名的服務器,同時在提交數據的時候希望能監測到文件上傳的實時進度。
自動發起的 OPTIONS 請求,其請求頭包含了的一些關鍵性字段:
OPTIONS /upload HTTP/1.1 Access-Control-Request-Method: POST Access-Control-Request-Headers: accept, content-type Origin: http://xxx.com ...
在這種場景下,客戶端發起的這個 OPTIONS 可以說是一個“預請求”,用於探測后續真正需要發起的跨域 POST 請求對於服務器來說是否是安全可接受的,因為跨域提交數據對於服務器來說可能存在很大的安全問題。
請求頭 Access-Control-Request-Method 用於提醒服務器在接下來的請求中將會使用什么樣的方法來發起請求。
那么在服務端應該如何處理這個 OPTIONS 請求呢?
這里以 node.js 服務器的 Koa 框架為例。在服務端會增加一個 OPTIONS 方法的 /upload 路由來處理客戶端的這個請求。
Koa 中使用了一個比較受歡迎的 koa-router 中間件來處理路由,但是該中間件對 OPTIONS 方法默認的處理方式會有點問題。因為在響應上面的 OPTIONS 請求時,需要添加上用於訪問控制的響應頭。
響應頭中關鍵性的字段:
Access-Control-Allow-Methods: POST Access-Control-Allow-Origin: http://xxx.com Access-Control-Allow-Headers: accept, content-type
Access-Control-Allow-Methods 和 Access-Control-Allow-Origin 分別告知客戶端,服務器允許客戶端用於跨域的方法和域名。而 Access-Control-Allow-Headers 用於告知客戶端允許在發送請求時允許添加或修改的請求頭。
node.js 的路由代碼會是這樣的:
router.options('/upload', function* (){ this.set('Access-Control-Allow-Methods', 'POST'); this.set('Access-Control-Allow-Origin', 'http://xxx.com'); this.set('Access-Control-Allow-Headers', 'Content-type'); this.status = 204; });
上面倒數第二行的代碼也很重要,設置響應狀態碼為 204 是為了告知客戶端表示該響應成功了,但是該響應並沒有返回任何響應體,如果狀態碼為 200,還得攜帶多余的響應體,在這種場景下是完全多余的,只會浪費流量。
關於 204 狀態碼的意義我經常會在面試的時候問起,這里就是一個實際應用的例子 ^_^
好了,OPTIONS 的請求處理完了,剩下的 POST 請求就簡單了,只需在響應頭中添加一條和 OPTIONS 一致的允許跨域的域名即可,這里就不重復粘貼代碼了。