80

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

There must be additional logic... I don't know how to properly code the Options method or if the controller is even the proper place to put the code. Weird (to me) that the Web API site responds properly when viewed from Firefox or Chrome, yet the .ajax call above errors out. How do I handle the "preflight" check in the .ajax code? Maybe I should be addressing this issue on the client side's .ajax logic? Or, if this is an issue on the server side due to not handling the OPTIONS verb.

Can anyone help? This must be a very common issue and I apologize if it's been answered here. I searched but didn't find any answers that helped.

UPDATE IMHO、これはクライアント側の問題であり、上記の 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,

It just seems that there should be a better solution available than modifying core code in JQuery...

The answer provided below assumes this is a server-side issue. Maybe, I guess, but I lean toward clients, and calling a hosting provider isn't going to help.

4

11 に答える 11

94

マイク・グッドウィンの答えは素晴らしいですが、試してみると、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 };
    }
  }
于 2014-01-30T14:14:29.833 に答える
52

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

全体像を完成させるために、AJAX 要求には追加の「Origin」ヘッダーがあり、JavaScript をホストしている元のページがどこから提供されたかを識別します。サーバーは、任意のオリジンからのリクエストをサポートするか、既知の信頼できるオリジンのセットのみをサポートするかを選択できます。任意のオリジンを許可すると、クロス サイト リクエスト フォージェリ (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 aa コントローラーまたはグローバル レベルを有効にすると、サポートされる HTTP 動詞
  • サーバーがクロスオリジン要求による資格情報の送信をサポートしているかどうか

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

どのブラウザーが CORS をサポートしているかに関して、ウィキペディアによると、次のエンジンが CORS をサポートしています。

  • ヤモリ 1.9.1 (ファイアフォックス 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

于 2013-09-30T18:02:53.693 に答える
24

これをメソッドに追加するだけで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 リクエストが有効になることに注意してください (代わりに、オリジン/URL のカンマ区切りのリストのみを許可することもできます)。

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

webconfigまた、セクションで削除と配置、パッチ、およびオプションの動詞を有効にする必要がありますsystem.webServer。そうしないと、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>

お役に立てれば

于 2015-10-29T07:45:46.107 に答える
11

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 を統合モードに設定する必要があります。

于 2016-09-13T14:38:27.793 に答える
8

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

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

リクエスト方法はGETHEAD、またはPOSTおよび

アプリケーションは、、、、、または、および以外の要求ヘッダーを設定しAcceptませAccept-LanguageContent-LanguageContent-TypeLast-Event-ID

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 (「プリフライト リクエスト」の下)

于 2014-01-23T20:58:53.107 に答える
3

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

于 2015-10-08T12:54:14.353 に答える
2
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 405 && Context.Request.HttpMethod == "OPTIONS" )
        {
            Response.Clear();
            Response.StatusCode = 200;
            Response.End();
        }
    }
于 2015-09-29T09:24:11.087 に答える
1

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

これを 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>
于 2015-12-05T13:23:38.373 に答える
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 にアクセスできるようになりました。

于 2014-05-19T14:29:26.580 に答える
0
//In the Application_OnBeginRequest method in GLOBAL.ASX add the following:-  

var res = HttpContext.Current.Response;  
var req = HttpContext.Current.Request;  
res.AppendHeader("Access-Control-Allow-Origin", "*");  
res.AppendHeader("Access-Control-Allow-Credentials", "true");  
res.AppendHeader("Access-Control-Allow-Headers", "Authorization");  
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();
    }

//Remove any entries in the custom headers as this will throw an error that there's to  
//many values in the header.  

<httpProtocol>
    <customHeaders>
    </customHeaders>
</httpProtocol>
于 2020-08-30T11:56:17.333 に答える