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

Angular中如何获取响应内容及自定义响应头?

Angular中获取Spring Boot异常响应内容及自定义响应头的问题

问题场景

Angular项目嵌入JSP页面,向Spring Boot后端发送带多部分文件的POST请求。当文件大小超过10MB时,Spring Boot抛出MaxUploadSizeExceededException,已通过全局异常处理器封装为EsignError格式返回,并添加自定义响应头msgHeader。浏览器Network标签能看到完整响应内容和自定义头,但Angular组件/Interceptor中无法正确获取。

后端代码实现

全局异常处理器EsignExceptionHandler

@ControllerAdvice
@Slf4j
public class EsignExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value
            = {EsignException.class})
    public ResponseEntity<Object> scannerException(Exception ex, WebRequest request) {
        log.error(ex.getMessage());
        log.info("Inside first handler");
        String bodyOfResponse = ex.getMessage();
        return handleExceptionInternal(ex, bodyOfResponse,
                HTTPUtil.getCommonHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
    }
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public @ResponseBody ResponseEntity<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException ex) {
        log.error(ex.getMessage());
        log.info("Inside second handler");
        EsignError error = new EsignError(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
        HttpHeaders headers = new HttpHeaders(HTTPUtil.getCommonHeaders());
        headers.setAccessControlAllowOrigin("*");
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("msgHeader", ex.getMessage());
        return new ResponseEntity<>(error, headers, HttpStatus.BAD_REQUEST);
    }

}

EsignError类定义

@Data
public class EsignError {
    private int status;
    private String message;
    private Date timestamp;

    public EsignError(int status, String message) {
        this.status = status;
        this.message = message;
        this.timestamp = new Date();
    }
}

后端返回示例响应

{ 
  "status": 400, 
  "message": "Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException: the request was rejected because its size (31238283) exceeds the configured maximum (10485760)", 
  "timestamp": "2022-11-17T08:41:45.580+00:00" 
}

Angular组件代码(postFile方法)

postFile() {
  this.uploadState = 'отправка файла...';

  var certHolders: string = '';
  this.corresp.approvals.forEach(a => {
    certHolders = certHolders + a.logname + ';';
  });

  const formData: FormData = new FormData();
  formData.append('file', this.file, 'file.pdf');
  formData.append('idappli', String(this.corresp.idappli));
  formData.append('odcorresp', String(this.corresp.odcorresp));
  formData.append('idletter', String(this.corresp.idletter));
  formData.append('certHolders', certHolders);
  formData.append('fpage', String(this.stampStart));
  formData.append('lpage', String(this.stampEnd));


  const headers = new HttpHeaders().append("Access-Control-Allow-Origin", "*")
    .append("Access-Control-Allow-Origin", "*")
    .append("Access-Control-Allow-Methods", "POST")
    .append("Access-Control-Allow-Headers", "Origin, Accept, Authorization, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers")

  const o: Observable<any> = this.http.post(this.corresp.url, formData, {headers, responseType: "blob"});
  o.subscribe(blob => {

      this.addHistory("insert");
      this.getFileWithSign();
      this.corresp.exists = true;
      console.log('blob.error: ' + blob.error);
      console.log('blob.message: ' + blob.message);
    },

    error => {
      this.uploadState = 'ошибка отправки файла на подпись!';
      console.log('console.log error.status: ' + error.status);
      // console.log('console.log error.error(): ' + error.error());
      // console.log('console.log error.errorDetails: ' + error.errorDetails);
      console.log('console.log error: ' + error);
      console.log('console.log error.error: ' + error.error);
      // The following line results in error in browser console: ERROR TypeError: Cannot read properties of undefined (reading 'status')
      // console.log('console.log error.error.status: ' + error.error.status);
      if (error.status === 400) {
        const msg2 = error.headers.get('msgHeader');
        alert('msg2: ' + msg2);
      }

    }
  );
}

解决方案

1. 后端配置自定义头暴露

跨域场景下,自定义响应头必须通过Access-Control-Expose-Headers主动暴露给前端,否则Angular无法读取。修改后端异常处理器的header配置:

// 在handleMaxUploadSizeExceededException方法中添加
headers.add("Access-Control-Expose-Headers", "msgHeader");

2. Angular端调整错误响应处理

当前请求设置了responseType: "blob",错误响应的error是Blob对象,需先转换为JSON才能解析EsignError内容:

error => {
  this.uploadState = 'ошибка отправки файла на подпись!';
  console.log('console.log error.status: ' + error.status);
  
  // 解析Blob类型的错误响应
  if (error.error instanceof Blob) {
    const reader = new FileReader();
    reader.onload = () => {
      const errorData = JSON.parse(reader.result as string);
      console.log('错误状态:', errorData.status);
      console.log('错误消息:', errorData.message);
    };
    reader.readAsText(error.error);
  }

  // 获取自定义响应头
  if (error.status === 400) {
    const msg2 = error.headers.get('msgHeader');
    alert('msg2: ' + msg2);
  }
}

3. 移除Angular请求中冗余的CORS头

Access-Control-Allow-Origin等属于后端返回的响应头,前端请求时无需手动携带,简化请求配置:

// 移除手动添加的CORS相关头,Angular会自动处理跨域请求
const o: Observable<any> = this.http.post(this.corresp.url, formData, {responseType: "blob"});

4. Interceptor中获取响应头(可选)

若使用Interceptor统一处理错误,需确保在HttpErrorResponse中读取头,同时后端已完成自定义头暴露:

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  constructor() {}

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
      catchError((error: HttpErrorResponse) => {
        // 获取自定义响应头
        const msgHeader = error.headers.get('msgHeader');
        console.log('自定义头msgHeader:', msgHeader);

        // 解析Blob类型错误
        if (error.error instanceof Blob) {
          return from(new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => {
              const errorData = JSON.parse(reader.result as string);
              reject(new HttpErrorResponse({
                ...error,
                error: errorData
              }));
            };
            reader.readAsText(error.error);
          }));
        }

        return throwError(() => error);
      })
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:51:16