代码之家  ›  专栏  ›  技术社区  ›  resting

.net MVC 4.5“选项”404未找到[重复]

  •  0
  • resting  · 技术社区  · 6 年前

    我已经用MVC 4/web API模板建立了一个ASP.NET web应用程序。似乎一切都很顺利,我不知道有什么问题。我用了Chrome和Firefox浏览了这个网站。我已经用小提琴测试过了,所有的反应似乎都在钱上。

    所以现在我继续编写一个简单的Test.aspx来使用这个新的Web API。剧本的相关部分:

    <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>
    

    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方法。

    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 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动词而出现的问题。

    更新 IMHO,这是一个客户端问题,与上面的Ajax JQuery代码有关。我这么说是因为Fiddler在我从web浏览器访问mywebapidomain/api/user时没有显示任何405个错误头。我唯一能重复这个问题的地方是JQuery.ajax()调用。另外,当在服务器(同一个域)上运行时,上面相同的Ajax调用也可以正常工作。

    我发现另一个帖子: Prototype AJAX request being sent as OPTIONS rather than GET; results in 501 error 这似乎是相关的,但我修改了他们的建议,但没有成功。显然,JQuery是这样编码的:如果Ajax请求是跨域的(我的请求是跨域的),那么它会添加一些头部,以某种方式触发OPTIONS头部。

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

    似乎应该有比在JQuery中修改核心代码更好的解决方案。。。

    0 回复  |  直到 7 年前
        1
  •  51
  •   Mike Goodwin    11 年前

    正如Daniel A.White在评论中所说,OPTIONS请求很可能是由客户机作为跨域JavaScript请求的一部分创建的。这是由跨源资源共享(CORS)兼容浏览器自动完成的。请求是初步的或 飞行前 请求,在实际的AJAX请求之前发出,以确定CORS支持哪些请求谓词和头。服务器可以选择支持无、全部或部分HTTP动词。

    为了完成这幅图,AJAX请求有一个额外的“Origin”头,它标识了承载JavaScript的原始页面的服务位置。服务器可以选择支持来自任何来源的请求,或者只支持一组已知的、可信的来源。允许任何来源都是一种安全风险,因为is会增加跨站点请求伪造(CSRF)的风险。

    所以,你需要启用CORS。

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

    这里描述的实现允许您指定

    • 支持的起源
    • 当启用CORS a控制器或全局级别时,支持的HTTP动词
    • 服务器是否支持发送具有跨源请求的凭据

    一般来说,这很好,但是您需要确保您知道安全风险,特别是当您允许来自任何域的跨源请求时。在你允许之前仔细考虑一下。

    在哪些浏览器支持CORS方面,Wikipedia表示以下引擎支持CORS:

    • WebKit(Safari 4、Chrome 3)
    • MSHTML/Trident 6(IE10),在IE8和9中提供部分支持
    • 普雷斯托(歌剧12)

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

        2
  •  90
  •   Oliver    11 年前

    Mike Goodwin的回答很好,但当我尝试的时候,它似乎是针对MVC5/WebApi 2.1的。 Microsoft.AspNet.WebApi.Cors的依赖关系与我的MVC4项目不太协调。

    注意,我已经允许了所有这些,我建议您将源代码限制为您希望API服务的客户机。允许一切都是一种安全风险。

    <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:

     public class BaseApiController : ApiController
      {
        public HttpResponseMessage Options()
        {
          return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
        }
      }
    
        3
  •  22
  •   Chtioui Malek    9 年前

    把这个加到你的 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-Credentials 为true将启用跨浏览器会话管理

    您还需要在 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>
    

    希望这有帮助

        4
  •  17
  •   defines    8 年前

    在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;
        }
    }
    

    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。

        5
  •  9
  •   lukalev    8 年前

    我已经成功地克服了405和404个错误,这些错误仅由global.asax中的自定义代码在飞行前ajax选项请求中抛出

    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();
            }
        }
    

    我不得不禁用CORS,因为它返回的“Access Control Allow Origin”头包含多个值。

    在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需要设置为集成模式。

        6
  •  7
  •   Richard Ev    7 年前

    我也有同样的问题。对我来说,修复方法是从jQuery AJAX调用中删除自定义内容类型。自定义内容类型触发飞行前请求。我发现这个:

    请求方法是 GET , HEAD ,或 POST ,

    应用程序不设置除 Accept , Accept-Language , Content-Language , Content-Type ,或 Last-Event-ID

    这个 标题(如果已设置)是以下之一:

    • 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 (在“飞行前请求”项下)

        8
  •  2
  •   yongfa365    9 年前
        protected void Application_EndRequest()
        {
            if (Context.Response.StatusCode == 405 && Context.Request.HttpMethod == "OPTIONS" )
            {
                Response.Clear();
                Response.StatusCode = 200;
                Response.End();
            }
        }
    
        9
  •  1
  •   Sudhanshu Mishra    10 年前

    我也面临同样的问题。

    按照以下步骤解决浏览器中(CORS)遵从性问题。

    包括对Web API解决方案的WebActivatorEx引用。

    [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。

        10
  •  1
  •   Erti-Chris Eelmaa    9 年前

    我也遇到过同样的问题,我就是这样解决的:

    <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>