Web API對application/json內容型別的CORS支援

Ken.W發表於2018-04-30

假設有一簡單架構分為前後兩部分,其一是Angular構成的前端頁面站點,另一個則是通過ASP.NET Web API搭建的後端服務站點。兩個站點因為分別佈署,所有會有CORS(Cross-Origin Resource Sharing)的問題。

再假設後端已經對此做好相應配置,比如在web.config里加上了:

  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
      <add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, HEAD" />
      <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
    </customHeaders>
  </httpProtocol>

那麼當前端呼叫後端介面:

  save(data: any) : Observable<any> {
      return this.http.post(`${this.apiUrl}`, data)
  }

後端對應介面內的邏輯理論上應該是能夠被正常執行的:

  [HttpPost]
  [Route("api/save")]
  public HttpResponseMessage Save(SomeModel model)
  {
      //內部邏輯
  }

但結果是出現了Message:"The requested resource does not support http method `OPTIONS`."錯誤。

產生此問題的原因在於HttpClient的post方法預設是採用application/json的內容型別(Content-Type)。

而CORS規範中有兩種型別:

  • Simple requests
  • Preflighted requests

前者無需額外的處理,但對於內容型別的支援,僅限三種:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

對於除此以外的內容型別,比如application/json,CORS會以預檢請求方式(Preflighted requests)處理。

Preflighted requests要求必須首先使用OPTIONS方法發起一個預檢請求到伺服器,以獲知伺服器是否允許該實際請求。

而在上面的後端服務程式碼中並沒有準備相應的處理OPTIONS請求的介面,所以才會有這樣的錯誤。

對應修正方法很簡單,在同一介面方法上加上處理OPTIONS請求的邏輯:

  [HttpOptions, HttpPost]
  [Route("api/save")]
  public HttpResponseMessage Save(SomeModel model)
  {
      if (Request.Method == HttpMethod.Options) return new HttpResponseMessage(HttpStatusCode.OK);
      //內部邏輯
  }

有關CORS的詳細描述,建議參考官方文件——Cross-Origin Resource Sharing (CORS)

相關文章