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

部署IIS后Blazor WASM登录用户POST/PUT/DELETE请求CORS失效

Blazor WASM + ASP.NET Core API 部署IIS后登录状态下CORS/405问题

问题概况

  • 技术栈:Blazor WebAssembly作为前端,标准C# REST API作为后端
  • 异常现象:未登录时CORS正常工作;用户登录后,所有POST、PUT、DELETE方法的端点均返回405 Method Not Allowed错误
  • 环境差异:本地开发环境一切正常,部署到Windows Server的IIS服务器后问题出现
  • 已排查:更换Chrome、Edge、Firefox等浏览器及不同设备测试,排除缓存旧配置的可能

相关请求截图描述

  • 未登录用户的预检请求截图
  • 登录用户的预检请求截图
  • 最终405错误截图

后端核心配置代码

CORS及认证授权主配置

var builder = WebApplication.CreateBuilder(args);

var corsSettings = builder.Configuration.GetSection(CorsSettings.SectionName).Get<CorsSettings>();
ArgumentNullException.ThrowIfNull(corsSettings, nameof(corsSettings));
builder.Services.AddCorsPolicy(corsSettings);

[...]

builder.Services.AddDbContext<AuthDbContext>(options => options.UseSqlite(connectionString));
builder.Services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<AuthDbContext>();

builder.Services.ConfigureApplicationCookie(options =>
{
    options.Cookie.HttpOnly = true;
    options.Cookie.Name = "GlossaryAuthCookie";
    options.Cookie.SameSite = SameSiteMode.Lax;
    options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
    
    options.Events.OnRedirectToLogin = context =>
    {
        context.Response.StatusCode = 401;
        return Task.CompletedTask;
    };
});

builder.Services.AddAuthentication().AddCookie();
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy(ClaimsNames.IsAdmin, policy => policy.RequireClaim(ClaimsNames.IsAdmin, ClaimsValues.True));
    options.AddPolicy(ClaimsNames.IsEditor, policy => policy.RequireClaim(ClaimsNames.IsEditor, ClaimsValues.True));
    options.AddPolicy(ClaimsNames.IsActive, policy => policy.RequireClaim(ClaimsNames.IsActive, ClaimsValues.True));
});

[...]

var app = builder.Build();

app.UseRouting();

app.UseCors(corsSettings.PolicyName);

app.UseAuthentication();
app.UseAuthorization();

app.UseSwagger();
app.UseSwaggerUI();

app.MapControllers();
app.MapGet("/", () => "PW Glossary API");

app.Run();

AddCorsPolicy扩展方法实现

serviceCollection.AddCors(options =>
{
    options.AddPolicy(corsSettings.PolicyName, policyBuilder =>
    {
        policyBuilder.AllowCredentials();

        if (corsSettings.AllowedHeaders.All(x => x.Equals("*")))
            policyBuilder.AllowAnyHeader();
        else
            policyBuilder.WithHeaders(corsSettings.AllowedHeaders);
        
        if (corsSettings.AllowedMethods.All(x => x.Equals("*")))
            policyBuilder.AllowAnyMethod();
        else
            policyBuilder.WithMethods(corsSettings.AllowedMethods);
        
        if (corsSettings.AllowedOrigins.All(x => x.Equals("*")))
            policyBuilder.AllowAnyOrigin();
        else
            policyBuilder.WithOrigins(corsSettings.AllowedOrigins);
        
    });
});

前端Blazor WASM配置代码

HttpClient与Refit客户端配置

builder.Services.AddRefitClient<IBackendApi>()
    .ConfigureHttpClient(httpClient => httpClient.BaseAddress = new Uri(backendUrl))
    .AddHttpMessageHandler<CookieHandler>();

CookieHandler实现

public class CookieHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> 
        SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.SetBrowserRequestMode(BrowserRequestMode.Cors);
        request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);

        return await base.SendAsync(request, cancellationToken);
    }
}

Refit接口示例

[Put("/api/glossary/")]
Task<ApiResponse<UpdateGlossaryEntryResponse>> UpdateGlossaryEntryAsync([Body] UpdateGlossaryEntryRequest request);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 11:32:01