You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core中预检请求与实际请求一致引发数据异常求助

解决ASP.NET Core跨域预检请求被转为POST的问题

一、问题根源

浏览器发送的OPTIONS预检请求到后端变成POST,基本都是反向代理(Nginx、IIS这类)配置出错——代理没保留原始请求方法,或者把OPTIONS请求错误转成了POST,导致后端无法区分预检和实际请求,进而触发两次API调用。

二、具体解决步骤

1. 修正反向代理配置

Nginx场景:

直接在配置里处理OPTIONS预检请求,同时转发时保留原始请求方法:

server {
    # 其他原有配置...

    # 直接处理OPTIONS预检,返回204响应
    if ($request_method = OPTIONS) {
        add_header Access-Control-Allow-Origin $http_origin;
        add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
        add_header Access-Control-Allow-Headers 'Content-Type, X-Request-ID, X-Real-IP, Authorization';
        add_header Access-Control-Allow-Credentials 'true';
        add_header Content-Length 0;
        add_header Content-Type text/plain;
        return 204;
    }

    # 转发请求到ASP.NET Core服务,必须保留原始请求方法
    location / {
        proxy_pass http://你的ASP.NET Core服务地址;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # 关键:传递原始请求方法
        proxy_set_header Request-Method $request_method;
    }
}

IIS场景:

检查URL重写规则是否篡改了OPTIONS请求,同时在web.config里配置预检响应:

<system.webServer>
    <rewrite>
        <rules>
            <rule name="转发到ASP.NET Core" stopProcessing="true">
                <match url="(.*)" />
                <action type="Rewrite" url="http://你的ASP.NET Core服务地址/{R:1}" />
                <!-- 确保不对OPTIONS请求做额外改写 -->
                <conditions>
                    <add input="{REQUEST_METHOD}" pattern="OPTIONS" negate="false" />
                </conditions>
            </rule>
        </rules>
    </rewrite>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
            <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
            <add name="Access-Control-Allow-Headers" value="Content-Type, X-Request-ID, X-Real-IP, Authorization" />
            <add name="Access-Control-Allow-Credentials" value="true" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

2. 调整ASP.NET Core中间件顺序

CORS中间件必须放在路由和授权中间件之前,不然没法提前拦截预检请求:

var builder = WebApplication.CreateBuilder(args);

// 注册CORS策略
builder.Services.AddCors(cors =>
{
    cors.AddPolicy("bundle_cors", builder =>
    {
        builder
            .AllowAnyHeader()
            .AllowAnyMethod()
            .WithExposedHeaders("set-cookie")
            .AllowCredentials()
            .SetIsOriginAllowed(_ => true);
    });
});

builder.Services.AddControllers();

var app = builder.Build();

// 关键:UseCors要放在UseRouting和UseAuthorization前面
app.UseCors("bundle_cors");

app.UseRouting();

app.UseAuthorization();

app.MapControllers();

app.Run();

3. 控制器层临时过滤(应急方案)

如果暂时改不了代理配置,就在控制器加个全局过滤器,直接拦截OPTIONS请求:

// 全局CORS预检过滤器
public class CorsPreflightFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.HttpContext.Request.Method == HttpMethod.Options.Method)
        {
            var origin = context.HttpContext.Request.Headers["Origin"].ToString();
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", origin);
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Headers", context.HttpContext.Request.Headers["Access-Control-Request-Headers"]);
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
            context.HttpContext.Response.StatusCode = StatusCodes.Status204NoContent;
            context.Result = new EmptyResult();
        }
    }

    public void OnActionExecuted(ActionExecutedContext context) { }
}

// 在Program.cs里注册过滤器
builder.Services.AddControllers(options =>
{
    options.Filters.Add<CorsPreflightFilter>();
});

三、验证方法

  1. 绕开代理,用Postman直接给ASP.NET Core服务发OPTIONS请求,确认后端能收到OPTIONS方法并返回204。
  2. 再用浏览器发起请求,看网络面板里OPTIONS请求返回204,实际POST请求只发一次。

内容的提问来源于stack exchange,提问作者Rustam Salakhutdinov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:15:06