Express+EJS项目图片无法渲染问题求助
EJS页面外部图片无法加载的解决方案
问题说明
练习EJS项目时,页面其他内容正常渲染,但图片无法显示。尝试从Express Session获取图片链接、直接使用图片URL均无效;生成的HTML源码中图片URL单独访问正常,但通过应用服务加载时无法渲染。
相关代码
app.js 文件
//Imports const path = require("path"); require("dotenv").config(); const express = require('express'); const morgan = require('morgan'); const helmet = require('helmet'); const partials = require('express-partials'); const app = express(); const session = require('express-session'); const passport = require('./config/passport.js'); //Variables const PORT = 3000; const EXPRESS_SESSION_SECRET = process.env.EXPRESS_SESSION_SECRET; //Remove after development to minimize unnecessary realtime logs on server app.use(morgan('tiny')); //Express setup app.use(express.json()); app.use(helmet()); app.disable('x-powered-by'); //Express page setup app.set('views', path.join(__dirname + '/views')); app.set('view engine', 'ejs'); app.use(partials()); app.use(express.static(path.join(__dirname + '/public'))); //Express session set up to be used on all routes app.use( session({ secret: EXPRESS_SESSION_SECRET, resave: false, saveUninitialized: false, cookie: { maxAge: 1000 * 60 *60 * 24 } }) ); //Initializes passport to be used on all routes app.use(passport.initialize()); app.use(passport.session()); //Mounts the page router const pageRouter = require('./routers/page-router.js'); app.use('/', pageRouter); //Mounts the api router const apiRouter = require('./routers/api-router.js'); app.use('/api', apiRouter); //Starts server app.listen(PORT, () => console.log(`Listening on ${PORT}`));
page-router.js 中/account的GET路由
//Imports necessary modules const express = require('express'); const {ensureAuthenticated} = require('../middleware/auth-middleware.js'); //Creates the router const pageRouter = express.Router(); //This page is protected and requires github authentication pageRouter.get('/account', ensureAuthenticated, (req, res) => { res.render('account', { user: req.user }); }); //Exports the router module.exports = pageRouter;
views/account.ejs 视图文件
<div class="row"> <div class="six columns"> <h1><%= user.username %></h1> <p>ID: <%= user.id %></p> <p>Name: <%= user.displayName %></p> <p>Bio: <%= user._json.bio %></p> <p>GitHub: <a href="<%= user._json.html_url %>">Link</a></p> </div> <div class="six columns"> <img src="<%= user.photos[0].value %>" alt="Avatar"> </div> </div>
生成的HTML源码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Codecademy OAuth Project</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css"> <link rel="stylesheet" href="css/normalize.css"> <link rel="stylesheet" href="css/skeleton.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> <div class="container"> <nav> <div> <a href="/">Home</a> | <a href="/account">Account</a> | <a href="/logout">Log Out</a> </div> </nav> <div class="row"> <div class="six columns"> <h1>brendengerber</h1> <p>Name: </p> <p>Bio: </p> <p>GitHub: <a href="https://github.com/brendengerber">Link</a></p> </div> <div class="six columns"> <img src="https://avatars.githubusercontent.com/u/10082638?v=4" alt="Avatar"> </div> </div> </div> </body> </html>
问题原因及解决方法
原因
项目中使用了helmet中间件,它默认会启用内容安全策略(CSP),限制页面只能加载同域资源。而头像图片来自外部域名(https://avatars.githubusercontent.com),因此被浏览器阻止加载。
解决步骤
- 验证问题:打开浏览器开发者工具(F12),查看控制台的报错信息,会看到CSP相关的拦截提示。
- 调整helmet配置:修改
app.js中的helmet调用,添加允许加载外部图片及其他必要资源的规则:
//Express setup app.use(express.json()); // 修改helmet配置,放开资源加载权限 app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], imgSrc: ["'self'", "https://avatars.githubusercontent.com"], styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"], fontSrc: ["'self'", "https://fonts.gstatic.com"] } } })); app.disable('x-powered-by');
- 开发阶段临时验证:如果只是开发测试,可以临时关闭CSP来快速确认问题:
app.use(helmet({ contentSecurityPolicy: false }));
修改后重启服务,即可正常加载外部头像图片。
内容的提问来源于stack exchange,提问作者Brenden
相关产品推荐
相关产品推荐

