IIS 部署网站对 OPTIONS 请求直接返回 40x 的处理

简介: 了解 OPTIONS 请求的基本功能、作用和大概拦截的原因,逐一排查,分别讲解在 asp.net (.net framework 时代)和 asp.net core (.net core/.net 时代) 的处理方式,OPTIONS 请求在不同的浏览器中默认请求行为表现不一致,通过设置 SetPreflightMaxAge (asp.net core 方式)的最大缓存时间,间接的优化...

什么是 OPTIONS 请求

OPTIONS 请求为 发送非简单跨域请求前的预检请求 ,若该请求未正常返回,浏览器会阻止后续的请求发送。

一般情况下,有三种方式会导致浏览器发起预检请求:

  1. 请求的方法不是 GET/HEAD/POST;
  2. POST 请求的 Content-Type 并非 application/x-www-form-urlencoded, multipart/form-data 或 text/plain;
  3. 请求中设置了自定义的 header 字段(如 Token);

显示 OPTIONS 请求

默认情况下,ChromeMicrosoft Edge 浏览器不会在 F12 工具的网络选项卡上显示 OPTIONS 请求。
要在这些浏览器中显示 OPTIONS 请求,请执行以下操作:

  • chrome://flags/#out-of-blink-cors 或 edge://flags/#out-of-blink-cors;
  • 禁用标记;
  • 重启;

Firefox 浏览器默认显示 OPTIONS 请求。

发送 OPTIONS 请求给服务器返回 404

若未对 IIS 进行配置,则会导致 OPTIONS 请求被 IIS 直接响应返回,而不会进入到代码中。这也是 Global 中的 Application_BeginRequest 无法捕获到 OPTIONS 请求的原因。
  1. 检查 webconfig 中的配置,是否移除了对 options 请求的特殊处理可在 IIS 中进行配置: [网站]-[应用程序]-[处理程序映射]
<system.webServer>
  <handlers>
    <remove name="OPTIONSVerbHandler" />
  </handlers>
</system.webServer>
  1. 检查 IIS 服务器是否安装了 UrlScan,若安装了请检查 AllowVerbs 中是否包含了 options ,可在 IIS 中查看是否安装了 UrlScan [网站]-[ISAPI筛选器] (可以找到 UrlScan 安装路径)

image.png

UrlScan 的配置文件为 UrlScan.ini (C:\Windows\System32\inetsrv\urlscan\UrlScan.ini)

OPTIONS 从 [DenyVerbs] 中移除并添加到 [AllowVerbs] 下。

  1. Global.asaxApplication_BeginRequest 实践中直接响应 OPTIONS 请求;
注意:该方式为 asp.net.net framework 时代)的处理
//允许所有的 `options` 请求,直接返回 `200` 状态码
private void Application_BeginRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.StatusCode = 200;
        HttpContext.Current.Response.Headers["Access-Control-Allow-Origin"] = HttpContext.Current.Request.Headers["origin"];
        HttpContext.Current.Response.End();
    }
}
  • Application_Start 和 Application_End

第一次访问站点时,创建 HttpApplication 对象,此时会触发 Application_Start,并创建HttpApplication 实例池,应用接请求就从池中获取实例,进行处理。在所有的 HttpApplication 实例闲置达到超时时间,触发应用程序池回收,或者重启站点时就会触发 Application_End 事件,应用程序池的闲置超时时间可以在 iis 设置,站点下 bin 目录下的文件发生改变,webconfig 配置改变等导致站点重启的事件都会触发 Application_End

  • Session_Start 和 Session_End

单个用户访问 Web 应用时,启动会话,服务器为该用户创建一个独立的 Session 对象,并触发Session_Start 事件,此时Session处于可用状态。用户在该会话建立后可以发起若干次请求,当服务器一段时间内未收到用户请求,达到会话超时时间时,触发 Session_End 事件,服务器释放为当前用户保存 Session 的内存。也可以在应用程序中调用 Session.Abandon() 可以手动取消 Session,清空服务器保存的 Session,直到再次调用 Session 时,又会触发 Session_Start,但是 SessionID 不会变化。所有会触发 Application_End 的事件都会在此之前触发 Session_Start。可以在 Web.Config 中添加设置 Session 过期时间( timeout 单位为分钟)。

  • Application_BeginRequest 和 Application_EndRequest

在用户会话启动后,每次发起的请求都会触发 Application_BeginRequest 事件,并在请求完成时触发 Application_EndRequest 事件。

  1. webconfig 中的 Allow-Method 中添加上 options
<system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Methods" value="OPTIONS,POST,GET" />
        <add name="Access-Control-Allow-Headers" value="x-requested-with,aspxauth" />
        <add name="Access-Control-Allow-Credentials" value="true" />
      </customHeaders>
    </httpProtocol>
</system.webServer>

发送 OPTIONS 请求给服务器返回 405

ajax 跨域在某些情况下会发送 OPTIONS 请求给服务器,如无相关设置会返回 405 错误,在 asp.net core 3.1 webapi 下通过中间件来处理 OPTIONS 请求。

  • OptionsRequestMiddleware 扩展中间件
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace Microsoft.AspNetCore.Builder
{
    /// <summary>
    /// 中间件
    /// </summary>
    public class OptionsRequestMiddleware
    {
        private readonly RequestDelegate _next;
 
        public OptionsRequestMiddleware(RequestDelegate next)
        {
            _next = next;
        }
 
        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Method.ToUpper() == "OPTIONS")
            {
                context.Response.StatusCode = 200;
                return;
            }
 
            await _next.Invoke(context);
        }
    }
 
    /// <summary>
    /// 扩展中间件
    /// </summary>
    public static class OptionsRequestMiddlewareExtensions
    {
        public static IApplicationBuilder UseOptionsRequest(this IApplicationBuilder app)
        {
            return app.UseMiddleware<OptionsRequestMiddleware>();
        }
    }
}
  • Startup.cs 里面的 Configure 中使用扩展中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 {
      ...
      app.UseOptionsRequest(); // 使用扩展中间件
      ...
 }

asp.net core 中优化 OPTIONS 请求

ASP.NET Core 中启用跨源请求 (CORS):了解更多请查看 => https://docs.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-6.0

在跨域策略中设置 SetPreflightMaxAge

// 添加跨域策略
services.AddCors(options =>
{
    string corsPolicyName = _config["CorsPolicyName"]; // 自定义跨域策略名称
    options.AddPolicy(corsPolicyName, builder =>
    {
        builder.AllowAnyOrigin() // 允许任何来源的主机访问
        //.AllowAnyHeader() // 允许任何的Header头部标题
        .WithHeaders("Account", "ClientType", "OrgId", "Token", "Department", "EntAuthVebr") // 自定义请求头
        //.AllowAnyMethod() // 允许任何方法
        .WithMethods(HttpMethods.Options, HttpMethods.Get, HttpMethods.Post, HttpMethods.Put, HttpMethods.Delete) // 允许的谓词方法
        .SetPreflightMaxAge(TimeSpan.FromHours(24)); // 设置预检请求的最大缓存时间
    });
});

...

app.UseCors(corsPolicyName); //使用跨域

总结

了解 OPTIONS 请求的基本功能、作用和大概拦截的原因,逐一排查,分别讲解在 asp.net.net framework 时代)和 asp.net core (.net core/.net 时代) 的处理方式,OPTIONS 请求在不同的浏览器中默认请求行为表现不一致,通过设置 SetPreflightMaxAge (asp.net core 方式)的最大缓存时间,间接的优化 OPTIONS 请求,减少服务器环境的预检测次数,你是否也遇到类似的问题呢?

目录
相关文章
|
4月前
IIS上实现网站朝https://www的自动跳转
我们在做网站时时常有网站朝https://www的自动跳转的需求,以便在不输入www.子域名时也可以自动跳转到我们的当前站点,本文将介绍实现网站朝https://www的自动跳转的操作。
68 0
IIS上实现网站朝https://www的自动跳转
|
4月前
|
程序员 网络安全 PHP
IIS使用PHPManager发布PHP网站
PHPManager是一款用于IIS(Internet Information Services)的工具,旨在简化在Windows服务器上发布PHP网站的过程。通过PHPManager,用户可以轻松管理PHP版本、配置PHP设置以及进行PHP应用程序的部署。这个工具提供了直观的用户界面,使用户能够更方便地与IIS服务器进行交互,而不需要深入了解服务器配置的技术细节。PHPManager的使用使得在IIS环境中托管和维护PHP网站变得更加便捷,提高了网站的部署效率和管理灵活性。
34 0
|
4月前
|
网络安全 PHP 开发者
IIS服务器发布PHP网站
IIS服务器,相信开发者都不会陌生,它的英文全称是Internet Information Services,是由微软公司提供的基于运行Microsoft Windows的互联网基本服务,常用于Windows系统的Web项目部署,本篇以PHP项目为例,讲解如何使用IIS完成PHP项目的发布。
56 0
|
2月前
|
存储 网络安全 数据安全/隐私保护
Windows Server 2019 IIS HTTPS证书部署流程详解
Windows Server 2019 IIS HTTPS证书部署流程详解
|
2月前
|
JavaScript Windows
VUE部署到IIS中报404错误解决方案-配置URL重写
VUE部署到IIS中报404错误解决方案-配置URL重写
|
2月前
|
Kubernetes 网络安全 Windows
要在云效部署到阿里云服务器上的 Windows Server 上的 IIS
【2月更文挑战第18天】要在云效部署到阿里云服务器上的 Windows Server 上的 IIS
168 4
|
4月前
|
前端开发 PHP
IIS发布PHP网站常见错误:字体库404
笔者最近在用IIS发布php网站时,前端出现了字体库文件404的错误,关于这个问题,尝试了很多办法,最终发现是字体文件类型不被IIS识别导致的,解决方法是在config文件中添加映射配置,下面我就来详细介绍下。
34 5
|
5月前
|
前端开发 JavaScript BI
云LIS云实验室信息管理系统源码,支持IIS独立部署,Docker部署
云LIS云实验室信息管理系统源码,支持IIS独立部署,Docker部署
55 0
|
7月前
宝塔中对IIS网站开启跨域限制
宝塔中对IIS网站开启跨域限制
39 0
|
10月前
|
安全 API 开发者
让IIS支持.NET Web Api PUT和DELETE请求
让IIS支持.NET Web Api PUT和DELETE请求