options预请求

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了options预请求相关的知识,希望对你有一定的参考价值。

参考技术A

最近开发过程中,为了避免跨域,于是在服务端添加了 Access-Control-Allow-Origin ,前端出现一个小异常,每次请求次数都是2次,第一次请求的 methods 为 options ,第二次才是正式的请求。每个接口请求2次很浪费资源,百度了下,这个请求叫做预请求,现在就来学习下。

跨域请求资源时浏览器为确认请求来源的安全性,会在正式的请求之前做一次预校验请求,待服务器允许之后才能发送正式的请求,这个预校验请求就是 options 请求。

并不是每次跨域资源请求都会发送 options 请求,当跨域请求为简单请求的时就不会发送预校验请求,当跨域请求为复杂请求时才会发送预校验请求。

什么是简单请求?

如果不满足以上条件的就是非简单请求。

预请求是浏览器的一种安全策略,但是它的存在给会占用浏览器的资源,影响页面的性能,所以要尽可能的减少 options 请求。而方法也很简单,使用简单请求即可:

注意以下几点:

如果以上没问题,但是还是有预请求的话,需要查看 header 里是否设置了其他参数,因为在项目开发中经常会将 token 放到 header 里进行传参,这种场景需要后端使用 Access-Control-Max-Age 。

Access-Control-Max-Age 的作用
用来指定本次预检请求的有效期,单位为秒,这样只有在第一次请求的时候会有 options ,之后浏览器会从缓存里读取响应,也就不会再发送 options 请求。
Access-Control-Max-Age 为 0 表示每次异步请求都发起预检请求,也就是说,发送两次请求。
Access-Control-Max-Age 为 1800 表示隔30分钟才发起预检请求。

Web Api 2 处理 OPTIONS 请求

【中文标题】Web Api 2 处理 OPTIONS 请求【英文标题】:Web Api 2 Handle OPTIONS Requests 【发布时间】:2016-07-27 00:35:26 【问题描述】:

我在 Azure 上托管了 Web Api 2 后端和 AngularJs forntend。我了解某些HTTP request 使用OPTIONS request 进行预检查。我的问题是如何以这种方式实现后端,如果控制器中有一些操作将处理 GET/POST/PUT/DELETE/... 之后的操作,那么所有 OPTIONS requests 都将返回 200。

【问题讨论】:

【参考方案1】:

我遇到了与您相同的问题,即所谓的 Preflight 请求,我发现这可能与 Web.Conf 文件的错误配置有关。 注释掉或删除(如果存在)包含 OPTIONSVerbHandler 的“删除”的行。

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

【讨论】:

你是英雄!【参考方案2】:

解决此任务的非优雅方法是手动添加每个控制器

[AcceptVerbs("OPTIONS")]
public HttpResponseMessage Options()

    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Headers.Add("Access-Control-Allow-Origin", "*");
    resp.Headers.Add("Access-Control-Allow-Methods", "GET,DELETE");

    return resp;

或者覆盖 MessageHandlers

 public class OptionsHttpMessageHandler : DelegatingHandler

  protected override Task<HttpResponseMessage> SendAsync(
  HttpRequestMessage request, CancellationToken cancellationToken)
  
    if (request.Method == HttpMethod.Options)
      
         var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();

          var controllerRequested = request.GetRouteData().Values["controller"] as string;              
          var supportedMethods = apiExplorer.ApiDescriptions.Where(d => 
               
                var controller = d.ActionDescriptor.ControllerDescriptor.ControllerName;
                return string.Equals(
                    controller, controllerRequested, StringComparison.OrdinalIgnoreCase);
            )
          .Select(d => d.HttpMethod.Method)
          .Distinct();

      if (!supportedMethods.Any())
         return Task.Factory.StartNew(
             () => request.CreateResponse(HttpStatusCode.NotFound));

      return Task.Factory.StartNew(() =>
        
            var resp = new HttpResponseMessage(HttpStatusCode.OK);
            resp.Headers.Add("Access-Control-Allow-Origin", "*");
            resp.Headers.Add(
                "Access-Control-Allow-Methods", string.Join(",", supportedMethods));

            return resp;
        );


return base.SendAsync(request, cancellationToken);

  

然后在配置中

GlobalConfiguration.Configuration.MessageHandlers.Add(new OptionsHttpMessageHandler());

即使是第二个选项也不是完美的...没有本地构建支持

【讨论】:

或从您自己的基类继承,其中包含您的公共 HttpResponseMessage Options() 方法:公共抽象类 BaseApiController : ApiController

以上是关于options预请求的主要内容,如果未能解决你的问题,请参考以下文章

HTTP options预请求

tomcat启用options请求

options请求问题

http options请求

HTTP协议详解(HyperText Transfer Protocol 超文本传输协议)访问控制(CORS) (OPTIONS预请求preflight request)浏览器同源策略

Web Api 2 处理 OPTIONS 请求