strict-dynamic 下 Vue 动态组件加载被 CSP 阻止怎么办?

夏侯梓轩 阅读 25

我在项目里启用了 CSP 的 strict-dynamic 策略,结果 Vue 的动态组件渲染直接被浏览器拦了,控制台报“Refused to execute inline script”。明明没写内联脚本啊,是不是 Vue 的模板编译触发了什么?

试过加 nonce 和 hash,但动态组件路径是变量,根本没法预知。现在卡在这儿了,求问怎么在保持 strict-dynamic 的前提下让 Vue 正常工作?

<template>
  <component :is="currentView" />
</template>

<script setup>
import Home from './views/Home.vue'
import About from './views/About.vue'

const currentView = ref(Home) // 或根据路由切换
</script>
我来解答 赞 2 收藏
二维码
手机扫码查看
2 条解答
柚溪(打工版)
这个问题我之前也踩过坑,其实不是你代码的问题,是 CSP 对动态脚本执行的限制比较严格。

先说原因,strict-dynamic 本身只信任带有 nonce 的脚本以及它动态创建的子元素。问题在于 Vue 的异步组件加载或者某些模板编译行为,在浏览器看来就是在"动态执行脚本",尤其如果你用了字符串形式的组件名或者动态 import。

解决思路有几个方向。

第一个方案,确保所有组件都是预编译的静态导入。你现在的代码其实已经是这样了,如果还被拦,检查一下 Vue 构建版本。确保用的是 runtime-only 版本,别用带编译器的完整版。带编译器的版本会在运行时编译模板,这个行为会被 CSP 拦截。在 vite 或 webpack 配置里确认一下 alias 指向 vue.runtime.esm-browser.js 或类似的 runtime-only 入口。

第二个方案,如果你需要真正的动态加载组件,用 defineAsyncComponent 配合动态 import,而且要确保构建工具把这些 import 预处理成单独的 chunk。

import { defineAsyncComponent } from 'vue'

const AsyncComponent = defineAsyncComponent(() =>
import('./views/SomeComponent.vue')
)


这样构建工具会提前把组件打包成独立文件,运行时只是动态加载已经编译好的 JS,不会触发运行时编译。

第三个方案,如果以上都不行,检查你的 CSP header 配置。strict-dynamic 需要配合一个有效的 nonce 或 hash 才能生效。确保你的主 JS 文件带了正确的 nonce 属性,而且服务端每次响应都要生成新的 nonce 值。



还有个容易忽略的点,检查项目里有没有用 v-html 或者字符串模板,比如 template: '
...
'
这种写法。这些都会触发运行时编译,直接被 CSP 干掉。全部改成 .vue 单文件组件或者 render 函数。

浏览器兼容方面,老版本浏览器对 strict-dynamic 支持不完整,可能需要降级方案,不过现代浏览器基本都没问题了。

实在搞不定的话,把 CSP 改成 'unsafe-eval' 加 nonce 的组合,虽然安全性差一点但至少能跑。当然这是下策。
点赞 1
2026-03-01 14:19
宇文静依
当时我也卡在这儿,Vue 的动态组件在 strict-dynamic 下被拦,真不是你写错了,是 Vue 编译模板时偷偷注入了 inline script,哪怕你没写