1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Content-Type: 'application/json'のときのCORSエラー

Last updated at Posted at 2024-11-06

経緯

React + Web API(C#)でアプリを開発しています。
長いことnugetパッケージのアップデートを放置()していたので、更新していました。
ある程度直ってきたので、Reactとの動作確認を行ったところ、GETメソッドは問題なく通信できるのに、POST(+ Preflight)はCORSエラーになってしまい、機能しなくなっていました。

出てきたエラー

コンソール
Access to fetch at '' from origin 'https://localhost:3000' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
NetworkタブのStatusホバーで出てきたメッセージ
Cross-Origin Resource Sharing error: PrefilghtMissingAllowOriginHeader

前提条件

  • Web API (C#):
    フレームワークは.Net Framework 4.8
    Microsoft.AspNet.WebApi.Corsはv5.2.4からv5.3.0にアップデート
    CORSの設定は以下の3ヶ所

    App_Start/WebApiConfig.cs
    using System.Web.Http;
    
    namespace SampleApp
    {
      public static class WebApiConfig
      {
        public static void Register(HttpConfiguration config)
        {
          // 省略
          config.EnableCors();
        }
      }
    }
    
    Web.config
    <system.webServer>
      <!-- 省略 -->
      <httpProtocol>
        <customHeaders>
          <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, PATCH, DELETE" />
        </customHeaders>
      </httpProtocol>
    </system.webServer>
    
    各ApiController(共通)
    using System.Web.Http;
    using System.Web.Http.Cors;
    
    namespace SampleApp.Controllers
    {
      [EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]
      public class DefaultController : ApiController
      {
        [HttpGet]
        public IHttpActionResult Get()
        {
          return Ok();
        }
      }
    }
    
  • React:
    パッケージのreactのバージョンはv16.2.0
    通信はJSのfetchを使用。基本の形は以下の通り

    // GET, DELETE など
    fetch (url, {
      mode: 'cors', method: method, credentials: 'include',
    })
    
    // POST, PUT, PATCH など
    fetch (url, {
      mode: 'cors', method: method, credentials: 'include',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: body,
    })
    

原因

Request HeaderのContent-Typeに'application/json'を指定しているのに、Access-Control-Allow-HeadersにContent-Typeを"明示的に"追加していないことが原因でした。

詳しいことは以下の記事に書いてあります。

今回のケースに則して要点をまとめると、

セーフリクエストヘッダーであるContent-Typeを、Access-Control-Allow-Headersに追加する必要はない、Content-Typeが'application/json'の場合はセーフリクエストヘッダーではなくなるため、追加しなければいけない。

です。

修正

今回はWeb.configと各ApiControllerの修正でよさそうです。
※ローカルだけがcross-originとなり、それ以外はsame-originとなるため、ローカルだけ解消したことを確認しています。

Web.config
  <system.webServer>
    <!-- 省略 -->
    <httpProtocol>
      <customHeaders>
+       <add name="Access-Control-Allow-Origin" value="https://localhost:3000" />
+       <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, PATCH, DELETE" />
+       <add name="Access-Control-Allow-Credentials" value="true" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
各ApiController(共通)
  using System.Web.Http;
  using System.Web.Http.Cors;

  namespace SampleApp.Controllers
  {
-    [EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]
     public class DefaultController : ApiController
     {
        [HttpGet]
        public IHttpActionResult Get()
        {
           return Ok();
        }
     }
  }

蛇足1: EnableCorsAttributeは使えなかった

EnableCorsAttributeを使う方も試しましたが、解決できませんでした。

App_Start/WebApiConfig.cs
  using System.Web.Http;
+ using System.Web.Http.Cors;

  namespace SampleApp
  {
    public static class WebApiConfig
    {
      public static void Register(HttpConfiguration config)
      {
-       config.EnableCors();
+       var cors = new EnableCorsAttribute(
+                    "https://localhost:3000", 
+                    "Content-Type", 
+                    "GET, POST, OPTIONS, PUT, PATCH, DELETE");
+       cors.SupportsCredentials = true;
+       config.EnableCors(cors);
      }
    }
  }

Web.configと一緒に設定するとCross-Origin Resource Sharing error: MultipleAllowOriginValuesのCORSエラーになります。

image.png

ただ、Web.configの重複している設定を消してもPOSTでエラーになるのは変わらないので、使わないことにしました。

蛇足2: Credentialsがtrueの場合、Originに"*"を設定しても無効になる

公式のドキュメントを見ていると、以下のような記述が見つかりました。

CORS 仕様では、SupportsCredentials が true である場合、origins を "*" に設定しても無効であることが示されています。

すべて、"*"でした、、!
静かに直しておきます。

呟き

コンソールのエラー読むと、ちゃんと書いてありますね、、
エラーはちゃんと読もう!(自戒)

発生した疑問

時間があったら調べて解決したい疑問。

  1. Access-Control-Allow-系の値は、大文字小文字の区別があるのか
  2. ローカルでの開発の際、Access-Control-Allow-Origin"https://localhost:3000"としか書かずに、https://localhost:3001からアクセスしたら弾かれるのか
    →CORS的には弾きそうだけど、弾かれなかったのが不思議
  3. Access-Control-Allow-Headersなどに*, Content-Typeみたいな指定はできるのか
    →ChatGPTには無理だと言われた
  4. EnableCorsAttributeを使う方はなぜ上手くいかなかったのか
    →どこかで[EnableCors]をまとめて指定できるのがEnableCorsAttributeだと見た気がするけど、Web.configと両立できないなら使えないのは困る
  5. 各APIコントローラーにあるEnableCorsの指定は必要なのか
    →今回のソースのような指定なら、Web.configの設定だけで十分にも見える

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?