OPTIONS 方法在跨域請求(CORS)中的應用
OPTIONS 方法比較少見,該方法用於請求伺服器告知其支援哪些其他的功能和方法。通過 OPTIONS 方法,可以詢問伺服器具體支援哪些方法,或者伺服器會使用什麼樣的方法來處理一些特殊資源。可以說這是一個探測性的方法,客戶端通過該方法可以在不訪問伺服器上實際資源的情況下就知道處理該資源的最優方式。
既然比較少見,什麼情況下會使用這個方法呢?
最近在做跨域檔案上傳的時候,瀏覽器會自動發起一個 OPTIONS 方法到伺服器。
如果只是普通的 ajax 請求,也不會發起這個請求,只有當 ajax 請求綁定了 upload 的事件並且跨域的時候,就會自動發起這個請求。
01 |
var xhr = new XMLHttpRequest(); |
02 |
var url = 'http://api.xxx.com/upload' ; |
03 |
04 |
xhr.open( 'POST' , url); |
05 |
06 |
xhr.upload.addEventListener( 'progress' , function (){ |
07 |
// ... |
08 |
}, false ); |
09 |
10 |
xhr.upload.addEventListener( 'load' , function (){ |
11 |
// ... |
12 |
}, false ); |
13 |
14 |
xhr.upload.addEventListener( 'error' , function (){ |
15 |
// ... |
16 |
}, false ); |
17 |
18 |
xhr.upload.addEventListener( 'abort' ,function (){ |
19 |
// ... |
20 |
}, false ); |
21 |
22 |
xhr.send(data); |
上面的程式碼是在 xxx.com 域下發起了一個跨域的 POST 請求,期望提交資料到 api.xxx.com 這個域名的伺服器,同時在提交資料的時候希望能監測到檔案上傳的實時進度。
自動發起的 OPTIONS 請求,其請求頭包含了的一些關鍵性欄位:
1 |
OPTIONS /upload HTTP/1.1 |
2 |
Access-Control-Request-Method: POST |
3 |
Access-Control-Request-Headers: accept, content-type |
4 |
Origin: http: //xxx.com |
5 |
... |
在這種場景下,客戶端發起的這個 OPTIONS 可以說是一個“預請求”,用於探測後續真正需要發起的跨域 POST 請求對於伺服器來說是否是安全可接受的,因為跨域提交資料對於伺服器來說可能存在很大的安全問題。
請求頭 Access-Control-Request-Method 用於提醒伺服器在接下來的請求中將會使用什麼樣的方法來發起請求。
那麼在服務端應該如何處理這個 OPTIONS 請求呢?
這裡以 node.js 伺服器的 Koa 框架為例。在服務端會增加一個 OPTIONS 方法的 /upload 路由來處理客戶端的這個請求。
Koa 中使用了一個比較受歡迎的 koa-router 中介軟體來處理路由,但是該中介軟體對 OPTIONS 方法預設的處理方式會有點問題。因為在響應上面的 OPTIONS 請求時,需要新增上用於訪問控制的響應頭。
響應頭中關鍵性的欄位:
1 |
Access-Control-Allow-Methods: POST |
2 |
Access-Control-Allow-Origin: http: //xxx.com |
3 |
Access-Control-Allow-Headers: accept, content-type |
Access-Control-Allow-Methods 和 Access-Control-Allow-Origin 分別告知客戶端,伺服器允許客戶端用於跨域的方法和域名。而 Access-Control-Allow-Headers 用於告知客戶端允許在傳送請求時允許新增或修改的請求頭。
node.js 的路由程式碼會是這樣的:
1 |
router.options( '/upload' , function* (){ |
2 |
this . set ( 'Access-Control-Allow-Methods' , 'POST' ); |
3 |
this . set ( 'Access-Control-Allow-Origin' , 'http://xxx.com' ); |
4 |
this . set ( 'Access-Control-Allow-Headers' , 'Content-type' ); |
5 |
this .status = 204; |
6 |
}); |
上面倒數第二行的程式碼也很重要,設定響應狀態碼為 204 是為了告知客戶端表示該響應成功了,但是該響應並沒有返回任何響應體,如果狀態碼為 200,還得攜帶多餘的響應體,在這種場景下是完全多餘的,只會浪費流量。
關於 204 狀態碼的意義我經常會在面試的時候問起,這裡就是一個實際應用的例子 ^_^
好了,OPTIONS 的請求處理完了,剩下的 POST 請求就簡單了,只需在響應頭中新增一條和 OPTIONS 一致的允許跨域的域名即可,這裡就不重複貼上程式碼了。
原載於:雨夜帶刀’s Blog原文連結: http://stylechen.com/options-cors.html
如需轉載請以連結形式註明原載或原文地址。