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

.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"));
    }
}
解决方案
  1. 移除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
    }
  });
}
  1. 配置.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();
  1. 确保异常场景返回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>();
  1. 验证生产环境CORS配置
    使用curl或Postman请求接口,检查响应头是否包含Access-Control-Allow-Origin: http://10.17.40.93:3000;针对OPTIONS预检请求,确认服务端返回正确的CORS头信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 05:32:57