ASP.NET网站Ajax POST调用ASP.NET Core 6.0 Web API的CORS问题排查
ASP.NET网站POST请求API遇401未授权问题排查
问题描述
我有一个ASP.NET网站(非Web应用),使用jQuery 2.1.4向ASP.NET Core 6.0 Web API发起Ajax POST请求时返回401 Unauthorized错误,但向同一控制器的其他GET接口请求完全正常。初步怀疑这不是单纯的CORS问题,可能涉及认证配置或请求处理逻辑。
相关代码与配置
Ajax POST请求代码
function insertLNItemStorageRequirement() { var tempLNStorage = { TItem: storageTempReq.t_item, TSrq1: storageTempReq.t_srq1, TSrq2: storageTempReq.t_srq2, TSq27: storageTempReq.t_sq27, TStmp: storageTempReq.t_stmp, TRcdVers: 0, TRefcntd: 0, TRefcntu: 0, }; $.ajax({ type: "POST", url: commonAPIURL + "api/LN/InsertItemStorageRequirement", data: JSON.stringify(tempLNStorage), contentType: "application/json; charset=utf-8", //dataType: "json", xhrFields: { withCredentials: true }, success: function (response) {}, failure: function (response) { alert(response.responseText); }, error: function (response) { alert(response.responseText); }, }); }
Web API接口方法
[HttpPost("InsertItemStorageRequirement")] [Produces(typeof(IActionResult))] public IActionResult InsertItemStorageRequirement([FromBody] Ttccgs016424 itemStorageReq) { Ttccgs016424 newItemStorageReq = _LN.Ttccgs016424s.FirstOrDefault(s => s.TItem == itemStorageReq.TItem); if (newItemStorageReq == null) { newItemStorageReq = new Ttccgs016424() { TItem = itemStorageReq.TItem, TSrq1 = itemStorageReq.TSrq1, TSrq2 = itemStorageReq.TSrq2, TSq27 = itemStorageReq.TSq27, TStmp = itemStorageReq.TStmp, TRcdVers = itemStorageReq.TRcdVers, TRefcntd = itemStorageReq.TRefcntd, TRefcntu = itemStorageReq.TRefcntu }; try { _LN.Ttccgs016424s.Add(newItemStorageReq); _LN.SaveChanges(); } catch (Exception ex) { return BadRequest(ex.Message); } return StatusCode(StatusCodes.Status201Created); } else { return StatusCode(StatusCodes.Status412PreconditionFailed, "Item Storage Requirement already exists."); } }
API的CORS配置(Startup.cs)
已将请求源加入origins数组:
services.AddCors(setup => { setup.DefaultPolicyName = "open"; setup.AddDefaultPolicy(p => { p.AllowAnyHeader(); p.WithMethods("OPTIONS", "GET", "POST", "PUT", "DELETE"); p.WithOrigins(origins); p.AllowCredentials(); }); });
请求头与响应头
OPTIONS预检请求头
OPTIONS /api/LN/InsertItemStorageRequirement HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate, br, zstd Accept-Language: en-US,en;q=0.9 Access-Control-Request-Headers: content-type Access-Control-Request-Method: POST Connection: keep-alive Host: localhost:31227 Origin: http://localhost:14612 Referer: http://localhost:14612/ Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-site User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Mobile Safari/537.36 Edg/128.0.0.0
响应头
HTTP/1.1 401 Unauthorized Cache-Control: private Content-Type: text/html; charset=utf-8 Server: Microsoft-IIS/10.0 WWW-Authenticate: Negotiate WWW-Authenticate: NTLM X-Powered-By: ASP.NET Date: Wed, 11 Sep 2024 23:43:25 GMT Content-Length: 5995
已尝试操作与更新
- 修改Ajax请求,使用
credentials: 'include'替代xhrFields.withCredentials: true,无效。 - 调整请求data格式为
'{itemStorageReq: "' + JSON.stringify(tempLNStorage) + '"}',无效。 - 确认IIS已安装CORS模块。
- 调整中间件顺序,将
app.UseCors("open")移至app.UseRouting()之后、app.UseAuthentication()之前:
app.UseRouting(); app.UseCors("open"); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
- 考虑到端点路由下CORS模块不会自动响应OPTIONS请求,计划添加如下预检处理方法,尚未验证:
[HttpOptions("InsertItemStorageRequirement")] public IActionResult PreFlightRoute() { return NoContent(); }
排查建议
- 检查认证中间件对OPTIONS请求的处理:GET请求成功说明认证通道正常,但OPTIONS预检请求触发401,可能是NTLM/Negotiate认证要求OPTIONS请求也携带凭证。可在ASP.NET Core认证配置中添加规则,允许OPTIONS请求跳过认证。
- 禁用IIS CORS模块测试:同时启用ASP.NET Core CORS中间件和IIS CORS模块可能导致冲突,暂时禁用IIS的CORS模块,仅使用ASP.NET Core的配置验证是否解决问题。
- 简化API接口测试:暂时移除
[FromBody]参数,将接口改为直接返回200状态码,测试预检请求是否能通过,排除模型绑定错误导致的隐性拦截。 - 验证CORS配置的准确性:确认请求Origin完全匹配
WithOrigins中的值(包括端口、协议),AllowCredentials()与Ajax的withCredentials配置保持一致。 - 启用详细日志排查:在API的
appsettings.json中设置日志级别为Debug,查看OPTIONS请求的完整处理流程,确认是认证中间件拦截还是CORS中间件未正确响应。
内容的提问来源于stack exchange,提问作者ben.kansas
相关产品推荐
相关产品推荐

