web-dev-qa-db-ja.com

ASP.NET MVC / WebAPIアプリケーションでHTTP OPTIONS動詞をサポートする方法

MVC 4/Web APIテンプレートで始まるASP.NET Webアプリケーションをセットアップしました。物事は本当にうまく機能しているように見えます-私が認識している問題はありません。私はChromeとFirefoxを使用してサイトにアクセスしました。私はFiddlerを使用してテストしましたが、すべての回答はお金にかかっているようです。

そこで、この新しいWeb APIを使用するための簡単なTest.aspxの作成に進みます。スクリプトの関連部分:

<script type="text/javascript">
    $(function () {

        $.ajax({
            url: "http://mywebapidomain.com/api/user",
            type: "GET",
            contentType: "json",
            success: function (data) {

                $.each(data, function (index, item) {

                    ....

                    });
                }
                );

            },
            failure: function (result) {
                alert(result.d);
            },

            error: function (XMLHttpRequest, textStatus, errorThrown) {
                alert("An error occurred, please try again. " + textStatus);
            }

        });

    });
</script>

これにより、REQUESTヘッダーが生成されます。

OPTIONS http://Host.mywebapidomain.com/api/user HTTP/1.1
Host: Host.mywebapidomain.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://mywebapidomain.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: content-type
Connection: keep-alive

現状では、Web APIは405 Method Not Allowedを返します。

HTTP/1.1 405 Method Not Allowed
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 30 Sep 2013 13:28:12 GMT
Content-Length: 96

<Error><Message>The requested resource does not support http method 'OPTIONS'.</Message></Error>

OPTIONS動詞がデフォルトでWeb APIコントローラーに接続されていないことを理解しています...そこで、UserController.csに次のコードを配置しました。

// OPTIONS http-verb handler
public HttpResponseMessage OptionsUser()
{
    var response = new HttpResponseMessage();
    response.StatusCode = HttpStatusCode.OK;
    return response;
}

...これにより、405 Method Not Allowedエラーがなくなりましたが、応答は完全に空です-データは返されません。

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 30 Sep 2013 12:56:21 GMT
Content-Length: 0

追加のロジックが必要です... Optionsメソッドを適切にコーディングする方法や、コードを配置する適切な場所がコントローラーであるかどうかもわかりません。 Firefox(またはChrome)から表示したときにWeb APIサイトが適切に応答するのに(上記の.ajax呼び出しでエラーが発生する)奇妙なことです(私には)。 .ajaxコードで「プリフライト」チェックを処理するにはどうすればよいですか?クライアント側の.ajaxロジックでこの問題に対処する必要がありますか?または、これがOPTIONS動詞を処理しないためにサーバー側で問題になる場合。

誰でも助けることができますか?これは非常に一般的な問題であり、ここで回答されている場合は謝罪します。私は検索しましたが、助けになる答えは見つかりませんでした。

UPDATE私見、これはクライアント側の問題であり、上記のAjax JQueryコードに関係しています。これは、Webブラウザからmywebapidomain/api/userにアクセスするときにFiddlerが405エラーヘッダーを表示しないためです。この問題を再現できる唯一の場所は、JQuery .ajax()呼び出しです。また、サーバー(同じドメイン)で実行した場合、上記の同じAjax呼び出しは正常に機能します。

私は別の投稿を見つけました: プロトタイプAJAXリクエストはGETではなくOPTIONSとして送信されます; 501エラーが発生します それは関連しているようですが、成功せずに提案をいじくりました。どうやら、JQueryはAjaxリクエストがクロスドメイン(私の場合)である場合、OPTIONSヘッダーをトリガーするヘッダーをいくつか追加するようにコーディングされているようです。

'X-Requested-With': 'XMLHttpRequest',
'X-Prototype-Version': Prototype.Version,

JQueryのコアコードを変更するよりも優れたソリューションがあるはずです...

以下の回答では、これはサーバー側の問題であると想定しています。たぶん、私は推測しますが、私はクライアントに寄りかかっており、ホスティングプロバイダーを呼び出すことは助けにはなりません。

77
rwkiii

Daniel A. Whiteがコメントで述べたように、OPTIONSリクエストは、クロスドメインJavaScriptリクエストの一部としてクライアントによって作成される可能性が高いです。これは、Cross Origin Resource Sharing(CORS)準拠のブラウザーによって自動的に行われます。要求は、実際のAJAX要求の前に行われる予備またはpre-flight要求であり、どの要求動詞とヘッダーがサポートされているかを判別しますCORSの場合。サーバーは、HTTP動詞のなし、すべて、または一部に対してサポートすることを選択できます。

図を完成させるために、AJAXリクエストには追加の「Origin」ヘッダーがあり、JavaScriptをホストしている元のページの提供元を特定します。サーバーは、任意のオリジンからのリクエストをサポートするか、既知の信頼できるオリジンのセットのみをサポートするかを選択できます。 Originを許可すると、クロスサイトリクエストフォージェリ(CSRF)のリスクが増加する可能性があるため、セキュリティリスクです。

そのため、CORSを有効にする必要があります。

ASP.Net Web APIでこれを行う方法を説明するリンクを次に示します。

http://www.asp.net/web-api/overview/security/enabling-cross-Origin-requests-in-web-api#enable-cors

そこで説明されている実装により、特に指定することができます

  • アクションごと、コントローラーごと、またはグローバルベースでのCORSサポート
  • サポートされている起源
  • コントローラまたはグローバルレベルでCORSを有効にすると、サポートされるHTTP動詞
  • サーバーがクロスオリジンリクエストによる資格情報の送信をサポートしているかどうか

一般に、これは正常に機能しますが、特に任意のドメインからのクロスオリジンリクエストを許可する場合は、セキュリティリスクに注意する必要があります。これを許可する前に非常に慎重に考えてください。

どのブラウザーがCORSをサポートしているのかについて、Wikipediaは次のエンジンがCORSをサポートしていると述べています。

  • Gecko 1.9.1(FireFox 3.5)
  • WebKit(Safari 4、Chrome 3)
  • IE8および9で部分的にサポートされているMSHTML/Trident 6(IE10)
  • プレスト(オペラ12)

http://en.wikipedia.org/wiki/Cross-Origin_resource_sharing#Browser_support

48
Mike Goodwin

Mike Goodwinの答えは素晴らしいですが、試してみたところ、MVC5/WebApi 2.1を対象としていたようです。 Microsoft.AspNet.WebApi.Corsの依存関係は、MVC4プロジェクトではうまく機能しませんでした。

MVC4を使用してWebApiでCORSを有効にする最も簡単な方法は次のとおりです。

すべてを許可していることに注意してください。Originを、APIを提供したいクライアントのみに制限することをお勧めします。すべてを許可することはセキュリティ上のリスクです。

Web.config:

<system.webServer>
    <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>
</system.webServer>

BaseApiController.cs:

OPTIONS http動詞を許可するためにこれを行います

 public class BaseApiController : ApiController
  {
    public HttpResponseMessage Options()
    {
      return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
    }
  }
89
Oliver

これをApplication_OnBeginRequestメソッドに追加して(これによりアプリケーションでCORSサポートがグローバルに有効になります)、プリフライトリクエストを「処理」します。

var res = HttpContext.Current.Response;
var req = HttpContext.Current.Request;
res.AppendHeader("Access-Control-Allow-Origin", req.Headers["Origin"]);
res.AppendHeader("Access-Control-Allow-Credentials", "true");
res.AppendHeader("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
res.AppendHeader("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");

// ==== Respond to the OPTIONS verb =====
if (req.HttpMethod == "OPTIONS")
{
    res.StatusCode = 200;
    res.End();
}

*セキュリティ:これにより、任意の場所からサーバーへのajaxリクエストが有効になることに注意してください(代わりに、コンマ区切りのOrigins/urlのリストのみを許可できます)。

*の代わりに現在のクライアントOriginを使用しました。これにより資格情報が許可されるため、=> Access-Control-Allow-Credentialsをtrueに設定すると、クロスブラウザセッション管理が有効になります。

また、webconfigセクションsystem.webServerでdeleteおよびput、patch、options動詞を有効にする必要があります。そうでない場合、IISはそれらをブロックします。

<handlers>
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

お役に立てれば

22
Chtiwi Malek

Web API 2プロジェクトで同じ問題に遭遇した後(そして、ここに入る価値のない理由で標準のCORSパッケージを使用できない場合)、カスタムDelagatingHandlerを実装することでこれを解決できました。

public class AllowOptionsHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        if (request.Method == HttpMethod.Options &&
            response.StatusCode == HttpStatusCode.MethodNotAllowed)
        {
            response = new HttpResponseMessage(HttpStatusCode.OK);
        }

        return response;
    }
}

Web API構成の場合:

config.MessageHandlers.Add(new AllowOptionsHandler());

ここに投稿された他の回答のいくつかと同様に、Web.configでCORSヘッダーも有効にしていることに注意してください。

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
    <remove name="WebDAVModule" />
  </modules>

  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
      <add name="Access-Control-Allow-Headers" value="accept, cache-control, content-type, authorization" />
      <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    </customHeaders>
  </httpProtocol>

  <handlers>
    <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    <remove name="TRACEVerbHandler" />
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  </handlers>
</system.webServer>

私のプロジェクトにはMVCは含まれず、Web API 2のみが含まれていることに注意してください。

15
defines

Global.asaxのカスタムコードによってのみ、プリフライトajaxオプションリクエストでスローされる405および404エラーを克服できました。

protected void Application_BeginRequest()
    {            
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            //These headers are handling the "pre-flight" OPTIONS call sent by the browser
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
            HttpContext.Current.Response.End();
        }
    }

PS:すべてを許可する場合は、セキュリティの問題を考慮してください*。

'Access-Control-Allow-Origin'ヘッダーに複数の値が含まれているため、CORSを無効にする必要がありました。

Web.configでもこれが必要でした:

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
  <remove name="OPTIONSVerbHandler"/>
  <remove name="TRACEVerbHandler"/>
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>

また、app.poolを統合モードに設定する必要があります。

8
lukalev

同じ問題がありました。私にとっての修正は、jQuery AJAX呼び出しからカスタムコンテンツタイプを削除することでした。カスタムコンテンツタイプは、プリフライトリクエストをトリガーします。私はこれを見つけました:

次の条件に該当する場合、ブラウザはプリフライトリクエストをスキップできます。

要求メソッドは、GETHEAD、またはPOSTandです。

アプリケーションは、AcceptAccept-LanguageContent-LanguageContent-Type、またはLast-Event-ID以外の要求ヘッダーを設定しません。 and

Content-Typeヘッダー(設定されている場合)は次のいずれかです。

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

このページから: http://www.asp.net/web-api/overview/security/enabling-cross-Origin-requests-in-web-api (「プリフライトリクエスト」の下)

7
Dominik

ASP.NET Web API 2では、CORSサポートが追加されました。リンクを確認してください[ http://www.asp.net/web-api/overview/security/enabling-cross-Origin-requests-in-web-api ]

3
refactor
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 405 && Context.Request.HttpMethod == "OPTIONS" )
        {
            Response.Clear();
            Response.StatusCode = 200;
            Response.End();
        }
    }
2
yongfa365

私は同じ問題を抱えていて、これが私がそれを修正した方法です:

あなたのweb.configでこれを投げるだけです:

<system.webServer>
    <modules>
      <remove name="WebDAVModule" />
    </modules>

    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Expose-Headers " value="WWW-Authenticate"/>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, PATCH, DELETE" />
        <add name="Access-Control-Allow-Headers" value="accept, authorization, Content-Type" />
        <remove name="X-Powered-By" />
      </customHeaders>
    </httpProtocol>

    <handlers>
      <remove name="WebDAV" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>
1

私も同じ問題に直面しました。

以下の手順に従って、ブラウザの(CORS)コンプライアンスに関する問題を解決します。

Corsリファレンスを使用して、ソリューションにREDRockを含めます。 Web APIソリューションへのWebActivatorEx参照を含めます。

次に、ファイルCorsConfigをWeb API App_Startフォルダーに追加します。

[Assembly: PreApplicationStartMethod(typeof(WebApiNamespace.CorsConfig), "PreStart")]

namespace WebApiNamespace
{
    public static class CorsConfig
    {
        public static void PreStart()
        {
            GlobalConfiguration.Configuration.MessageHandlers.Add(new RedRocket.WebApi.Cors.CorsHandler());
        }
    }
}

これらの変更が完了すると、すべてのブラウザーでwebapiにアクセスできました。

1