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

Angular 18 SSR项目禁用脚本优化仍遇内联脚本CSP违规

解决Angular 18 SSR项目内联脚本的CSP合规问题

你遇到的内联脚本是Angular SSR客户端hydration(水合)过程中自动注入的引导代码,和angular.json里的脚本优化配置无关——这段代码是框架用来启动客户端与服务端渲染内容同步的核心逻辑,默认会以内联方式执行。以下是彻底解决问题的步骤,无需添加'unsafe-inline':

1. 启用Angular的CSP Nonce支持

Nonce是每个请求唯一的随机字符串,Angular可以利用它标记合法的内联脚本,让CSP策略允许执行这些脚本:

配置angular.json

在项目的build.options中添加CSP配置,指定nonce占位符:

"projects": {
  "your-project-name": {
    "architect": {
      "build": {
        "options": {
          // 其他现有配置
          "csp": {
            "enabled": true,
            "nonce": "{{nonce}}"
          }
        }
      }
    }
  }
}

修改index.html

在页面头部添加带nonce占位符的CSP meta标签(同时服务端会通过响应头设置更优先级的CSP,这里做兜底):

<head>
  <!-- 其他meta标签 -->
  <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'nonce-{{nonce}}'; style-src 'self' 'unsafe-inline';">
</head>

2. 在SSR服务器端生成并注入Nonce

修改你的SSR入口文件(通常是server.ts),生成随机nonce,传递给Angular渲染上下文,并在响应头中设置带nonce的CSP:

import { randomBytes } from 'crypto';
import { NONCE } from '@angular/core';
import { renderApplication } from '@angular/platform-server';
import { AppServerModule } from './src/main.server';
import { readFileSync } from 'fs';

const indexHtml = readFileSync('./dist/your-project/browser/index.html', 'utf-8');

// 处理请求的逻辑中
server.get('*', async (req, res) => {
  // 生成唯一nonce
  const nonce = randomBytes(16).toString('base64');
  
  // 渲染应用时注入nonce
  const html = await renderApplication(AppServerModule, {
    document: indexHtml.replace('{{nonce}}', nonce),
    url: req.url,
    providers: [
      { provide: NONCE, useValue: nonce }
    ]
  });

  // 设置响应头CSP,包含nonce
  res.setHeader(
    'Content-Security-Policy',
    `script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline';`
  );
  
  res.send(html);
});

3. 可选:禁用Hydration(不推荐)

如果你的项目不需要SSR的交互水合能力,可以直接禁用hydration,彻底消除这段内联脚本:
在app.config.ts中配置:

import { ApplicationConfig, provideClientHydration } from '@angular/core';

export const appConfig: ApplicationConfig = {
  providers: [
    provideClientHydration({
      disableHydration: true
    })
    // 其他providers
  ]
};

注意:禁用hydration会让SSR页面失去客户端交互能力,变成纯静态渲染,仅适合纯展示类页面。

为什么之前禁用脚本优化没用?

你看到的内联脚本不属于Angular build阶段的优化产物,而是客户端初始化hydration时框架动态注入的引导代码,optimization.scripts: false只会影响打包后的脚本压缩和内联,对这段框架级的初始化脚本无效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:52:43