ASP.NET Core 8.0 Web API对接Terminal Four CMS时出现CORS错误
我搭建了一个ASP.NET Core 8.0 Web API,在Google脚本和手动编写的网站中都能正常运行,但通过内容管理系统Terminal Four调用时,抛出CORS错误:
从源'https://t4.something.edu'获取'https://a.someting.edu/Newsletter/api/newsletter'的请求被CORS策略阻止:对预检请求的响应未通过访问控制检查:不具有HTTP OK状态码。
我只做POST请求,搞不懂为什么在Google脚本和原生网站里没问题,CMS托管的网站就不行?
现有Program.cs代码
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { options.AddPolicy(name: MyAllowSpecificOrigins, policy => { policy.WithOrigins("https://t4.something.edu") .AllowAnyHeader() .AllowAnyMethod(); }); }); builder.Services.AddControllers(); // context IConfiguration config = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .AddEnvironmentVariables() .AddCommandLine(args) .AddUserSecrets<Program>(true) .Build(); builder.Services.AddDbContext<NewsletterContext>(option => { option.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")); }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddTransient<IApiKeyValidation, ApiKeyValidation>(); builder.Services.AddScoped<ApiKeyAuthFilter>(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseCors(MyAllowSpecificOrigins); app.UseAuthorization(); app.MapControllers(); app.Run();
Terminal Four中调用脚本
<script> function send() { var url = 'https://a.something.edu/News/api/news'; var headers = { 'X-API-Key' : "something1234", 'Accept': "application/json", 'Content-Type': "application/json;charset=utf-8" }; var data = { "email" : document.getElementById("customerEmail").value }; var payload = JSON.stringify(data); var options = { method: "POST", headers: headers, body: payload }; try { var response = fetch(url, options); }catch(error) { alert('Error is : ' + error); } alert('Response is - ' + response); } </script>
已尝试的操作
- 试过设置
mode: "no-cors",但触发415不支持的媒体类型错误 - Program.cs里已经配置了官方文档中的CORS中间件,问题依旧
- 目前在Web服务器的web.config里添加了全局响应头:
<system.webServer> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> </customHeaders> </httpProtocol> </system.webServer>
更新:控制器代码
[Route("api/[controller]")] [ApiController] public class NewsletterController(NewsletterContext context) : ControllerBase { private readonly NewsletterContext _context = context; [HttpPost] public async Task<ActionResult<NewsletterItem>> PostNewsletterItem(NewsletterItem newsletterItem) { _context.Newsletter_Emails.Add(newsletterItem); try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { throw; } return Ok("The record has been saved correctly"); } }
更新:模型代码
namespace NewsletterEmails.Models { public class NewsletterItem { [Key] public required string Email { get; set; } } }
问题分析与解决步骤
1. 预检请求失败的核心原因
你的请求包含自定义头X-API-Key,会触发OPTIONS预检请求。当前问题大概率出在以下两点:
- API密钥验证过滤器拦截了OPTIONS请求:你注册的
ApiKeyAuthFilter如果对所有请求(包括OPTIONS)做验证,而OPTIONS请求不会携带X-API-Key,会直接返回非200状态码,导致预检失败 - 响应头冲突:同时启用ASP.NET Core CORS中间件和IIS自定义头,会导致返回多个
Access-Control-Allow-Origin,浏览器拒绝这类响应
2. 针对性修复方案
方案一:修改API密钥过滤器,放行OPTIONS请求
在ApiKeyAuthFilter的OnActionExecuting方法中添加判断:
public override void OnActionExecuting(ActionExecutingContext context) { // 放行OPTIONS预检请求,无需验证API密钥 if (context.HttpContext.Request.Method == HttpMethod.Options.Method) { context.HttpContext.Response.StatusCode = StatusCodes.Status200OK; context.Result = new OkResult(); return; } // 原有API密钥验证逻辑... }
方案二:移除web.config中的全局CORS头
删除web.config里的<add name="Access-Control-Allow-Origin" value="*" />配置,完全由ASP.NET Core中间件处理CORS,避免响应头冲突。
方案三:检查请求路由匹配
前端脚本中的请求URL是https://a.something.edu/News/api/news,但错误信息里的URL是https://a.someting.edu/Newsletter/api/newsletter,确认是否存在拼写错误或路由不匹配——如果OPTIONS请求的路由不存在,会返回404导致预检失败。
方案四:显式指定允许的自定义头
虽然用了AllowAnyHeader(),可以显式指定允许X-API-Key头,避免潜在解析问题:
policy.WithOrigins("https://t4.something.edu") .AllowHeaders("X-API-Key", "Content-Type", "Accept") .AllowAnyMethod();
3. 验证手段
- 用Postman发送OPTIONS请求到目标API,查看响应状态码和CORS头是否正确
- 打开浏览器开发者工具的Network面板,查看OPTIONS请求的具体响应内容,确认是返回401、404还是其他错误
内容的提问来源于stack exchange,提问作者ScottH

