使用 express 和 helmet 服务的 React 应用程序无法发出 API 请求
React app served with express and helmet cannot make API requests
我正在使用 express 构建 React 应用程序。
const root = path.join(__dirname, 'build/');
app.use(express.static(root));
app.use((req, res, next) => {
if (req.method === 'GET' && req.accepts('html') && !req.is('json') && !req.path.includes('.')) {
res.sendFile('index.html', { root });
} else next();
});
一切正常。但是,一旦我将 helmet
(不是 react-helmet)添加到 express 应用程序,我就会遇到问题(样式和脚本未加载)。
在搜索了几个资源之后,我想出了一个解决方案来让它工作。
下面的代码显示了我为加载样式和脚本所做的修复。
app.use(helmet());
app.use(helmet.contentSecurityPolicy({
defaultSrc: [
'\'self\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
styleSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://*.googleapis.com',
'https://api.domain.tld/*',
'https://domain.tld',
],
scriptSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
contentSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
}));
此外,我还在 .env file
中添加了 INLINE_RUNTIME_CHUNK=false
。
我目前遇到的问题是我对 api.domain.tld
的 API 调用不起作用。它被阻止并在 firefox 上显示以下错误。
Content Security Policy: The page’s settings blocked the loading of a resource at https://api.domain.tld/endpoint (“default-src”).
Chrome 显示如下错误。
Refused to connect to 'https://api.domain.tld/endpoint' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.
- 请注意,React 应用在
domain.tld
上,API 在 api.domain.tld
上
如何解决这个问题,以便我可以拨打 API 电话?
根据 Documentation,您应该在 directives
中指定来源
app.use(helmet.contentSecurityPolicy({
useDefaults: false, // you can change it to `true` if you want.
directives:{
defaultSrc: [
'\'self\'',
'https://api.domain.tld/',
'https://domain.tld',
],
styleSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://*.googleapis.com',
'https://api.domain.tld/',
'https://domain.tld',
],
'image-src': [
'\'self\'',
'\'unsafe-inline\'',
'data:',
'https://api.domain.tld/',
'https://domain.tld',
],
scriptSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
contentSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/',
'https://domain.tld',
],
}
}));
更新
要解决图片无法加载的问题,请添加以下内容。
imageSrc: [
'\'self\'',
'\'unsafe-inline\'',
'data:',
'https://api.domain.tld/',
'https://domain.tld',
],
有 2 个问题:
修正语法错误:contentSrc:
-> connectSrc:
CSP 规范不允许在路径部分使用 *(通配符),因此请修复 'https://api.domain.tld/*
-> 'https://api.domain.tld/'
。同样在路径部分,您可以使用:
- 文件夹名称:
'https://api.domain.tld/real_path_here/'
(带尾部斜杠 /)- 将允许指定文件夹和子文件夹中的任何子文件夹和任何文件。
- 文件名:
'https://api.domain.tld/endpoint'
或 'https://api.domain.tld/some_path/script.js'
(不带尾部斜杠 /)- 仅允许指定 file_name。
我正在使用 express 构建 React 应用程序。
const root = path.join(__dirname, 'build/');
app.use(express.static(root));
app.use((req, res, next) => {
if (req.method === 'GET' && req.accepts('html') && !req.is('json') && !req.path.includes('.')) {
res.sendFile('index.html', { root });
} else next();
});
一切正常。但是,一旦我将 helmet
(不是 react-helmet)添加到 express 应用程序,我就会遇到问题(样式和脚本未加载)。
在搜索了几个资源之后,我想出了一个解决方案来让它工作。
下面的代码显示了我为加载样式和脚本所做的修复。
app.use(helmet());
app.use(helmet.contentSecurityPolicy({
defaultSrc: [
'\'self\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
styleSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://*.googleapis.com',
'https://api.domain.tld/*',
'https://domain.tld',
],
scriptSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
contentSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
}));
此外,我还在 .env file
中添加了 INLINE_RUNTIME_CHUNK=false
。
我目前遇到的问题是我对 api.domain.tld
的 API 调用不起作用。它被阻止并在 firefox 上显示以下错误。
Content Security Policy: The page’s settings blocked the loading of a resource at https://api.domain.tld/endpoint (“default-src”).
Chrome 显示如下错误。
Refused to connect to 'https://api.domain.tld/endpoint' because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.
- 请注意,React 应用在
domain.tld
上,API 在api.domain.tld
上
如何解决这个问题,以便我可以拨打 API 电话?
根据 Documentation,您应该在 directives
app.use(helmet.contentSecurityPolicy({
useDefaults: false, // you can change it to `true` if you want.
directives:{
defaultSrc: [
'\'self\'',
'https://api.domain.tld/',
'https://domain.tld',
],
styleSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://*.googleapis.com',
'https://api.domain.tld/',
'https://domain.tld',
],
'image-src': [
'\'self\'',
'\'unsafe-inline\'',
'data:',
'https://api.domain.tld/',
'https://domain.tld',
],
scriptSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/*',
'https://domain.tld',
],
contentSrc: [
'\'self\'',
'\'unsafe-inline\'',
'https://api.domain.tld/',
'https://domain.tld',
],
}
}));
更新
要解决图片无法加载的问题,请添加以下内容。
imageSrc: [
'\'self\'',
'\'unsafe-inline\'',
'data:',
'https://api.domain.tld/',
'https://domain.tld',
],
有 2 个问题:
修正语法错误:
contentSrc:
->connectSrc:
CSP 规范不允许在路径部分使用 *(通配符),因此请修复
'https://api.domain.tld/*
->'https://api.domain.tld/'
。同样在路径部分,您可以使用:
- 文件夹名称:
'https://api.domain.tld/real_path_here/'
(带尾部斜杠 /)- 将允许指定文件夹和子文件夹中的任何子文件夹和任何文件。 - 文件名:
'https://api.domain.tld/endpoint'
或'https://api.domain.tld/some_path/script.js'
(不带尾部斜杠 /)- 仅允许指定 file_name。