.NET 7+Angular16生产环境PDF下载接口出现No 'Access-Control-Allow-Origin'跨域错误
问题详情
基于.NET 7和Angular 16开发的应用中,多数客户端请求正常运行,但调用下载PDF文件的特定接口时,仅在生产环境触发CORS错误,Chrome控制台报错信息如下:
Access to XMLHttpRequest at 'http://10.17.40.93:5000/Report/GenerateEggResultsReport' from origin 'http://10.17.40.93:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
正常请求示例
Angular端代码
getUserResults(startDate: string): Observable<ResponseBase> { const params = new HttpParams() .set('startDate', startDate); return this.http.get<ResponseBase>(environment.apiUrl + 'Report/getUserResults', { params, headers: { 'LangInfo': this.baseService.currentLanguage.enumValue } }); }
.NET端代码
[HttpGet("GetUserResults")] public JsonResult GetUserResults(DateTime startDate, DateTime endDate, bool isOptoClass, EShiftType? shiftType) { try { var eggResults = _machineReportAppService.GetUserResults(startDate, endDate, isOptoClass, shiftType); return ResponseBase.StatusReturn(EReturnStatus.Success, eggResults); } catch (Exception ex) { var returnStatus = ex.Message == Translator.Translate("NoMachineOperationFound") ? EReturnStatus.CleanLoadedData : EReturnStatus.Error; var returnMessage = !ex.Message.IsNullOrEmpty() ? ex.Message : Translator.Translate("ErrorGettingEggResults"); return ResponseBase.StatusReturn(returnStatus, returnMessage); } }
异常请求示例
Angular端代码
generateReportFile(eggResultsReportFileRequest: EggResultsReportFileRequest): Observable<HttpResponse<Blob>> { return this.http.post<Blob>(environment.apiUrl + 'Report/GenerateEggResultsReportFile', eggResultsReportFileRequest, { observe: 'response', responseType: 'blob' as 'json', headers: { 'Access-Control-Allow-Origin': '*', 'LangInfo': this.baseService.currentLanguage.enumValue } }); }
.NET端代码
[HttpPost("GenerateEggResultsReportFile")] public IActionResult GenerateEggResultsReportFile(EggResultsReportFileRequest eggResultsReportFileRequest) { try { CreateLog(eggResultsReportFileRequest); var eggResultsReport = _machineReportAppService.GenerateEggResultsReportFile(eggResultsReportFileRequest); return File(eggResultsReport.ReportContent, eggResultsReport.ReportExtension); } catch { throw new InvalidOperationException(Translator.Translate("ErrorGeneratingReport")); } }
解决方案
- 移除Angular请求中的无效请求头
Access-Control-Allow-Origin是服务端返回给客户端的响应头,客户端发送该头不仅无效,还会触发预检OPTIONS请求,若服务端未正确处理则会引发CORS错误。修改后的Angular代码:
generateReportFile(eggResultsReportFileRequest: EggResultsReportFileRequest): Observable<HttpResponse<Blob>> { return this.http.post<Blob>(environment.apiUrl + 'Report/GenerateEggResultsReportFile', eggResultsReportFileRequest, { observe: 'response', responseType: 'blob' as 'json', headers: { 'LangInfo': this.baseService.currentLanguage.enumValue } }); }
- 配置.NET服务端CORS策略
确保生产环境中CORS策略允许http://10.17.40.93:3000来源,覆盖POST方法并应用到所有控制器。Program.cs配置示例:
var builder = WebApplication.CreateBuilder(args); // 注册CORS服务 builder.Services.AddCors(options => { options.AddPolicy("AllowReportOrigin", policy => { policy.WithOrigins("http://10.17.40.93:3000") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); // 若需携带凭证(如Cookie)则添加此行 }); }); // 其他服务注册... var app = builder.Build(); // 在路由前启用CORS app.UseCors("AllowReportOrigin"); // 其他中间件配置... app.Run();
- 确保异常场景返回CORS响应头
当前接口捕获异常后直接抛出,可能导致服务端未返回CORS头。添加全局异常处理中间件,保证异常场景下仍返回带CORS头的响应:
public class GlobalExceptionMiddleware { private readonly RequestDelegate _next; public GlobalExceptionMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { context.Response.StatusCode = StatusCodes.Status500InternalServerError; context.Response.ContentType = "application/json"; // 依赖UseCors中间件已添加CORS头 await context.Response.WriteAsync(System.Text.Json.JsonSerializer.Serialize(new { Status = "Error", Message = Translator.Translate("ErrorGeneratingReport") })); } } } // 在Program.cs中注册中间件(UseCors之后,UseRouting之前) app.UseMiddleware<GlobalExceptionMiddleware>();
- 验证生产环境CORS配置
使用curl或Postman请求接口,检查响应头是否包含Access-Control-Allow-Origin: http://10.17.40.93:3000;针对OPTIONS预检请求,确认服务端返回正确的CORS头信息。
内容的提问来源于stack exchange,提问作者guirms
相关产品推荐
相关产品推荐

