CORS命名策略必须显式注册并显式启用,缺一不可;AddCors()仅定义策略,UseCors("PolicyName")才启用,且名称大小写敏感、顺序须在UseRouting后UseAuthorization前。

CORS 命名策略必须显式注册 + 显式启用,缺一不可;只调用 AddCors() 不调用 UseCors("PolicyName"),策略完全不生效。
命名策略注册时必须指定唯一名称
注册策略时传入的字符串就是它的“身份证”,后续启用、控制器标注都依赖它。一旦拼错、大小写不一致(如注册 "AllowFrontend" 却在 UseCors("allowfrontend") 中使用),中间件会静默跳过,不报错也不生效。
-
AddCors()只是定义策略,不启用任何行为 - 一个
options.AddPolicy()调用对应一个命名策略,不能重复注册同名策略(会覆盖) - 推荐用 PascalCase 命名,比如
"PublicApi"、"AdminDashboard",避免下划线或空格 - 若需默认策略,可用
options.AddDefaultPolicy(),此时UseCors()可不带参数
UseCors() 必须传入匹配的策略名
中间件启用阶段不校验策略是否存在——传错名就等于没启用。尤其在 Minimal API 场景下,[EnableCors] 特性对 MapGet/MapPost 无效,只能靠 UseCors("xxx") 全局挂载。
- 顺序错误(如放在
UseAuthorization()之后)会导致预检请求(OPTIONS)被拦截为 401/403 - Minimal API 的 endpoint 映射(如
app.MapGet("/api/data", ...))必须在UseCors()之后,否则不覆盖 - 不要混用:全局
UseCors("A")+ 控制器上[EnableCors("B")],后者会被前者覆盖(除非用MapWhen分流)
WithOrigins() 和 WithCredentials() 不能共存于通配符
只要开了 WithCredentials()(即前端带 cookie 或 token),WithOrigins() 就不能用 "*",否则 .NET 启动时报错:System.InvalidOperationException: When requesting credentials, the 'Access-Control-Allow-Origin' header cannot be '*',浏览器也会直接拦截并提示 The value of the 'Access-Control-Allow-Origin' header... must not be the wildcard '*'。
- 正确写法:明确列出可信源,如
.WithOrigins("https://app.example.com", "http://localhost:5173") - 开发环境可临时加多个本地地址,但上线前必须清理测试域名
- 如果确实需要动态 Origin(如 SaaS 多租户),得绕过中间件,在 handler 中手动判断并写头——但要自己处理预检、
Access-Control-Allow-Headers、Access-Control-Max-Age等完整逻辑
AllowAnyMethod() 和 WithMethods() 行为差异很关键
AllowAnyMethod() 允许所有 HTTP 方法,并在预检响应中返回 Access-Control-Allow-Methods: *;而 WithMethods("GET", "POST") 只放行列表内的方法,且预检响应头也只列这些值。浏览器严格按该头决定是否发出真实请求。
- 如果前端发的是
PATCH,但策略只写了WithMethods("GET", "POST"),预检通过后真实请求仍被拒绝 -
AllowAnyMethod()在开发期方便,但生产环境建议显式限定,减少暴露面 -
WithMethods()支持大小写敏感的字符串,如"get"无效,必须用"GET"
最易被忽略的一点:策略里没写 WithExposedHeaders(),但前端 JS 试图读取自定义响应头(如 X-Total-Count、ETag),即使请求成功,JS 也拿不到——因为浏览器默认只暴露 Cache-Control、Content-Language 等少数几个标准头。


















