ASP.NET WebApi 內建跨網域支援(參考:進擊的 ASP.NET Web API 2 巨人 – 打造支援各種裝置及平台的服務 - MSDN 台灣部落格 ),但基於專案的特殊需求,最後我還是決定自己寫 CORS 支援。

程式在 IIS Express 測試正常,搬到 IIS 後部分呼叫正常,部分失效。經分析問題如下:

瀏覽器在發出跨網域請求時,若符合以下條件:(參考:MDN

  • It uses methods other than GET, HEAD or POST. 
    執行 GET/HEAD/POST 以外的方法
  • Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
    使用 POST 且使用 application/x-www-form-urlencoded, multipart/form-data, or text/plain 之外的 Content-Type,例如:以 POST 傳送 XML、JSON 等。
  • It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
    使用自訂 Header

瀏覽器會在正式 Request 發送前,先送出一個 OPTIONS 的行前檢查請求(Preflight Request)。例如以下範例,開啟 Chrome 連上 jQuery 官網,於 F12 開發工具主控台透過 jQuery.ajax 分別發出三個 Request 到本機 localhost(標準跨網域情境),第一個為 POST、第二個為 GET,第三個 POST Request 指定 ContentType="text/xml"[ 註:測試時誤寫成plain/xml(羞),寫到昏頭,但仍吻合條件,擷圖就容我偷懶不修正,順便當成彩蛋(謎:這樣也成?I 服了U) ]。前兩次測試都是單一 Request 完成,第三個測試則會先送出一個 OPTIONS 請求,接著才正式送出 POST。

同樣的測試搬到 IIS,重覆前述的第三個 Request,送出的 OPTIONS Preflight Request 會因 Server 端未正確傳回 Access-Control-Allow-Origin 而失敗!

探究其原因,在 IIS 失敗是因為 OPTIONS Request 被預設載入的 OPTIONSVerbHandler 攔截,直接回應,未傳回對應的 Access-Control-Allow-Origin 標頭,導致 CORS 呼叫失敗。

要校正問題,可透過 IIS 管理員介面或修改 web.config 將其移除:

  <system.webServer>
    <handlers>
      <remove name="OPTIONSVerbHandler" />
      <!-- 略 -->
    </handlers>
  </system.webServer>

測試結果便正常了!

註: 在 IIS8,該 Handler 名稱為 OPTIONS。參考


Comments

Be the first to post a comment

Post a comment