已启用 CORS,但在 POST JSON 时,预检响应的 HTTP 状态代码 404 无效

Posted

技术标签:

【中文标题】已启用 CORS,但在 POST JSON 时,预检响应的 HTTP 状态代码 404 无效【英文标题】:CORS enabled but response for preflight has invalid HTTP status code 404 when POSTing JSON 【发布时间】:2016-07-15 12:18:19 【问题描述】:

我已经彻底搜索,但在我的特定情况下找不到解决此问题的方法。

使用 Fiddler (POST) 的跨域服务调用正确执行并接收到数据。但是,通过浏览器 (Chrome) 我收到消息“预检有无效的 HTTP 状态代码 404”

我有一个 Web API 应用程序并安装了 CORS 并确保 web.config 文件中存在以下内容:

<system.webServer>
    <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>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
      </customHeaders>
    </httpProtocol>
</system.webServer>

这里是 Ajax 调用:

var secretKey = 'difusod7899sdfiertwe08wepifdfsodifyosey',
    url = 'http://api.intrinsic.co.uk/api/v1/PTS/ActiveDrivers?api_key=098werolllfWnCbPGAuIXVOJidDHRfYcgxImMlxTXopuekXrSOqOWzEAIdeNTWGPQPpyHxgVGsFysGFKPzq';

  jQuery.ajax (
      url: url,
      type: "POST",
      data: JSON.stringify( secretKey: secretKey),
      dataType: "json",
      contentType: "application/json; charset=utf-8",
      success: function(data)
          var content = "<table class=\"container\"><thead><tr><th>Driver Number</th><th>Timestamp</th><th>VRN</th><th>Latitude</th><th>Longitude</th><th>Track Link</th></tr></thead><tbody>";
          $.each(data.ActiveDrivers.DriverLocationStatus, function (index, element) 
              content += "<tr><td>" + element.DriverNumber + "</td>";
              content += "<td>" + dateFormat(element.Timestamp, "d/m/yy") + " " + dateFormat(element.Timestamp, "h:MM TT") + "</td>";
              content += "<td>" + element.VRN + "</td>";
              content += "<td>" + element.CurrentLatitude + "</td>";
              content += "<td>" + element.CurrentLongitude + "</td>";
              content += "<td><a href=\"https://www.google.co.uk/maps/place//@" + element.CurrentLatitude + "," + element.CurrentLongitude + ",15z/\" target='_blank'>Track &raquo;</a></td></tr>";
          );
          content += "</tbody></table>";
          $( "#result" ).html( content );
      
  );

显然,可以完美地在同一个域上运行,并且如上所述,它可以使用 Fiddler。

我确定是浏览器的预检选项检查对于“应用程序/json”的内容类型失败,但我不确定如何修复它。

web.config 文件中是否缺少我应该添加的内容?

我已尝试删除“内容类型”而没有任何影响。

我曾希望this article 能解决问题(看起来很有希望),但遇到了同样的错误:

XMLHttpRequest cannot load [URL]. Response for preflight has invalid HTTP status code 404

【问题讨论】:

【参考方案1】:

谢谢,但在上述配置更改后出现 405 错误。

在 web api Global.asax 文件中添加以下代码后,它终于可以工作了

protected void Application_BeginRequest(Object sender, EventArgs e)
    
        //HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        
            HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
            HttpContext.Current.Response.End();
        
    

【讨论】:

为什么这还不是答案?【参考方案2】:

我终于搞定了。

这篇文章'WebAPI with CORS – IIS Intercepts OPTIONS Verb'告诉了我的想法。一张图片显示了 IIS 中 OPTIONS 处理程序映射出现的位置,以及为什么我们需要在 web.config 中删除它以确保 IIS 不会拦截。

当我查看 IIS 时,那个处理程序并不存在。然后,我查看了链接文章“Can't set HttpHandler order using Web.Config unless a «clear» tag exists”,发现在本文中,删除 OPTION 处理程序后,它被显式添加到 web.config 中。

因为我在 IIS 中看不到 OPTION 处理程序,所以我也将它添加到 web.config 文件中,然后突然就开始工作了。看来这个添加是需要的。

最终的 web.config 处理程序部分如下所示(请注意,我决定保留最初的“删除”,以防万一将来我迁移到不同的 Web 服务器时出现问题)。

<system.webServer>
    <handlers>
      <remove name="WebDAV"/>
      <remove name="OPTIONSVerbHandler"/>
      <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" />
      <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" responseBufferLimit="4194304" />
    </handlers>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS" />
      </customHeaders>
    </httpProtocol>
</system.webServer>

【讨论】:

你能帮我解决这个问题吗:magento.stackexchange.com/questions/170342/… 感谢工作。添加处理程序也很重要。【参考方案3】:

这对我有用。

在 Global.asax 中

protected void Application_BeginRequest(Object sender, EventArgs e)

    //HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    
        HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    

在 Web.config 中

    <httpProtocol>
        <customHeaders>

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

重建并嘿presto。

【讨论】:

【参考方案4】:

当我试图让 CORS 在我的 Web 服务上运行时,我有一个类似的设置显示 404 错误和 500 错误。我的修复基本上使用了 Hussain 的解决方案,但是当我清理修复时,我注意到只需要一个响应行,并且我能够将原始 Web 处理程序保留在 web.config 中,并且不需要移动所有将响应处理程序放入代码中。

基本上,我的修复在我的 ApplicationOnBeginRequest 处理程序中包含了这个 ONE MAJOR FIX

    private void ApplicationOnBeginRequest( object sender, EventArgs eventArgs )
        
...
            if ( context.Request.HttpMethod == "OPTIONS" )
                response.End();
        

以及我的 web.config 中的这些处理程序:

<system.webServer>
    <!--Other handlers/modules ...-->
    <httpProtocol>
        <customHeaders>
            <clear />
            <add name="Access-Control-Allow-Origin" value="*" />
            <add name="Access-Control-Allow-Credentials" value="true" />
            <add name="Access-Control-Allow-Headers" value="Content-Type,Accept" />
            <add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
        </customHeaders>
    </httpProtocol>
   </system.webServer>

抱歉,我无法将此笔记作为对 Hussain 回答的评论发送。

【讨论】:

【参考方案5】:

对于使用 .NET Core 3.1 的用户,这里有一个完整的解决方案(前端到后端):

我的问题:当我在我的 Web API 上启用 Windows 身份验证时,我无法从我的 react 应用程序获取调用到我的 .NET Core 3.1 Web API,CORS 吓坏了。使用匿名身份验证它可以工作,但在启用 Windows 身份验证时不能。

1.launchSettings.json

这将仅用于您的开发环境,请确保您的产品服务器上的 IIS 中也启用了 Windows 身份验证。


  "iisSettings": 
    "windowsAuthentication": true,
    "anonymousAuthentication": false,
    "iisExpress": 
      "applicationUrl": "http://localhost:58747",
      "sslPort": 0
    
  ,
 ... more settings if any

2.Startup.cs:

CORS 政策在此处启用。方法的顺序在这里很重要。此外,您不需要在 web.config 中设置这些

public void ConfigureServices(IServiceCollection services)
    
        services.AddCors(options =>
        
            options.AddPolicy("CorsPolicy", //give it the name you want
                           builder =>
                           
                               builder.WithOrigins( "http://localhost:3000", //dev site
                                                    "production web site"
                                                   .AllowAnyHeader()
                                                   .AllowAnyMethod()
                                                   .AllowCredentials();
                           );
        );

        //database services here

        services.AddControllers();
    

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    
        if (env.IsDevelopment())
        
            app.UseDeveloperExceptionPage();
        

        app.UseRouting();

        // global policy same name as in the ConfigureServices()
        app.UseCors("CorsPolicy");

        app.UseEndpoints(endpoints =>
        
            endpoints.MapControllers();
        );
    

3.控制器:

using Microsoft.AspNetCore.Cors;
... your other usings

namespace ProjectTest.Controllers

    [ApiController]
    [EnableCors("CorsPolicy")] //THIS HERE needs to be the same name as set in your startup.cs
    [Route("[controller]")]
    public class FooController:Controller
    
        [HttpGet("getTest")]
        public JsonResult GetTest()
        
            return Json("bar");
        
    

4.React Component fetch 调用示例:

“凭据:'include'”是秘密

    await fetch('http://localhost:3000/Foo/getTest', 
        method: 'GET',
        credentials: 'include'
    ).then(resp => resp.json());

【讨论】:

【参考方案6】:

对于 asp 核心,请在配置过程中的 Startup.cs 中使用此代码。我用的是 2.0 版本,但我认为它也应该适用于旧版本

app.UseCors(builder => 
                builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
            );

【讨论】:

【参考方案7】:

这对我也有帮助,我已经在 web.config 中配置了 CORS

protected void Application_BeginRequest(Object sender, EventArgs e)

    //HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    
        HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    

【讨论】:

以上是关于已启用 CORS,但在 POST JSON 时,预检响应的 HTTP 状态代码 404 无效的主要内容,如果未能解决你的问题,请参考以下文章

发出 POST 请求时出现 Google Cloud Function CORS 错误

CORS 已启用,但 toDataURL 仍会引发警告

本地 Javascript Fetch Post 请求失败,调用 ASP.NET Core 2.2 Web API。 CORS 已启用

CORS 已启用,但仍出现 CORS 错误

CORS 已启用,但仍会收到 405

400 仅在启用 cors 时响应 asp.net web api POST 请求