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

Angular 17本地SSR+SSL环境下无法调用.NET Core后端求助

Angular 17.0.3迁移后Postman模拟爬虫请求API失败问题

问题背景

本地通过npm start运行Angular项目,启动命令配置如下:

"start": "ng serve  --ssl --ssl-cert %APPDATA%\\ASP.NET\\https\\%npm_package_name%.pem --ssl-key %APPDATA%\\ASP.NET\\https\\%npm_package_name%.key --host=127.0.0.1"

网站在浏览器中可正常访问,但使用Postman模拟Facebook爬虫请求URL时,前端无法调用.NET Core后端接口,自定义Http拦截器输出错误:

ErrorHandlerService 0 - "Http failure response for https://localhost:7093/api/Product/LoadProduct/21275402: 0 undefined"
Error
    at eval (c:/GitHub/iperedil/angularapp/src/app/error-handler.services.ts:25:37)
    at _Observable.init (c:/GitHub/iperedil/angularapp/node_modules/rxjs/dist/esm/internal/observable/throwError.js:5:51)
    at _Observable._trySubscribe (c:/GitHub/iperedil/angularapp/node_modules/rxjs/dist/esm/internal/Observable.js:37:25)
    at eval (c:/GitHub/iperedil/angularapp/node_modules/rxjs/dist/esm/internal/operators/catchError.js:14:31)

直接在浏览器中访问接口https://localhost:7093/api/Product/LoadProduct/21275402可正常返回数据,该问题为Angular 17.0.3迁移后出现。

注释拦截器部分代码后,获得更详细错误信息:

HttpErrorResponse {
  headers: _HttpHeaders {
    normalizedNames: Map(0) {},
    lazyUpdate: null,
    headers: Map(0) {}
  },
  status: 0,
  statusText: 'Unknown Error',
  url: 'https://localhost:7093/api/Product/LoadProduct/21275402',
  ok: false,
  name: 'HttpErrorResponse',
  message: 'Http failure response for https://localhost:7093/api/Product/LoadProduct/21275402: 0 undefined',
  error: TypeError: fetch failed
      at node:internal/deps/undici/undici:12345:11
      at _ZoneDelegate.invoke (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:368:26)
      at Object.onInvoke (c:/GitHub/iperedil/angularapp/node_modules/@angular/core/fesm2022/core.mjs:14424:33)
      at _ZoneDelegate.invoke (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:367:52)
      at _Zone.run (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:130:43)
      at eval (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:1191:36)
      at _ZoneDelegate.invokeTask (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:403:31)
      ... 2 lines matching cause stack trace ...
      at _ZoneDelegate.invokeTask (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:402:36) {
    cause: Error: self-signed certificate
        at TLSSocket.onConnectSecure (node:_tls_wrap:1674:34)
        at _ZoneDelegate.invokeTask (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:403:31)
        at eval (c:/GitHub/iperedil/angularapp/node_modules/@angular/core/fesm2022/core.mjs:14098:55)
        at AsyncStackTaggingZoneSpec.onInvokeTask (c:/GitHub/iperedil/angularapp/node_modules/@angular/core/fesm2022/core.mjs:14098:36)
        at _ZoneDelegate.invokeTask (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:402:36)
        at Object.onInvokeTask (c:/GitHub/iperedil/angularapp/node_modules/@angular/core/fesm2022/core.mjs:14411:33)
        at _ZoneDelegate.invokeTask (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:402:36)
        at _Zone.runTask (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:174:47)
        at invokeTask (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:484:34)
        at TLSSocket.ZoneTask.invoke (c:/GitHub/iperedil/angularapp/node_modules/zone.js/fesm2015/zone-node.js:473:48) {
      code: 'DEPTH_ZERO_SELF_SIGNED_CERT'

自定义Http拦截器代码

export class ErrorHandlerService implements HttpInterceptor {
  constructor(private router: Router, private authservice: AuthService) { }
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req)
      .pipe(
        catchError((error: HttpErrorResponse) => {
          console.log('ErrorHandlerService ' + error.status + ' - ' + JSON.stringify(error.message)); // HERE
          if (error instanceof HttpErrorResponse && error.status === 401 &&
          } else {
            return throwError(() => new Error(errorMessage));
          }
        })
      )
  } 

问题分析与解决方案

核心原因

从错误信息中的DEPTH_ZERO_SELF_SIGNED_CERT可知,问题根源是自签名证书不被Node.js环境信任。Angular 17默认使用Node.js的fetch API发起请求,而fetch会严格验证证书合法性;浏览器允许用户手动信任自签名证书,但Postman模拟爬虫请求时,前端在Node环境下的请求会被拦截。

解决方案

1. 开发环境临时方案

  • 禁用证书验证(仅本地开发)
    启动项目时添加环境变量跳过证书校验:

    set NODE_TLS_REJECT_UNAUTHORIZED=0 && npm start
    

    注意:此方法仅适用于本地开发,生产环境禁止使用。

  • 将自签名证书加入系统信任列表
    将%APPDATA%\ASP.NET\https\%npm_package_name%.pem证书导入系统根证书目录,Node.js会继承系统信任配置,无需修改代码。

2. 长期推荐方案

使用mkcert工具生成本地可信证书:

  1. 安装mkcert工具
  2. 生成并安装本地CA:
    mkcert -install
    
  3. 为localhost生成证书:
    mkcert localhost 127.0.0.1
    
  4. 修改Angular启动命令,使用新证书:
    "start": "ng serve --ssl --ssl-cert ./localhost.pem --ssl-key ./localhost-key.pem --host=127.0.0.1"
    

3. 拦截器代码修复

原拦截器存在语法错误(if语句未闭合),修复后代码如下:

export class ErrorHandlerService implements HttpInterceptor {
  constructor(private router: Router, private authservice: AuthService) { }
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req)
      .pipe(
        catchError((error: HttpErrorResponse) => {
          console.log('ErrorHandlerService ' + error.status + ' - ' + JSON.stringify(error.message));
          let errorMessage = '未知错误';
          if (error instanceof HttpErrorResponse) {
            if (error.status === 401) {
              // 处理401逻辑,例如跳转登录页
              this.router.navigate(['/login']);
              errorMessage = '未授权访问';
            } else {
              errorMessage = error.message || `错误状态码: ${error.status}`;
            }
          }
          return throwError(() => new Error(errorMessage));
        })
      );
  } 
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 15:45:56