使用res.render渲染.hbs文件时无法正常展示HTML表格
问题:Express中res.render渲染Handlebars时HTML标签未被解析
在Express项目中,我拼接了HTML表格字符串,使用res.send()时可正常展示表格样式,但调用res.render()渲染form_process_title.hbs文件时,表格的HTML标签被直接显示而非解析成表格。我期望通过res.render实现正常的HTML表格展示,相关代码如下:
GET路由代码
app.get('/data/search/title', (req, res, next) => { res.render('form_process_title', { name: 'Form Title' }); });
form_process_title.hbs代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Welcome to {{ name }} page</h1> <form method="POST" action="/form_route_title"> <input type="text" name="title" placeholder="title"> <input type="submit"> </form> <p>{{ans}}</p> </body> </html>
POST路由代码
app.post('/form_route_title', function (req, res, next) { var ans = "<table border = 3>"; ans += "<tr>"; ans += "<td>" + "Title" + "</td>"; ans += "<td>" + "ISBN" + "</td>"; ans += "<td>" + "Description" + "</td>" + "</tr>"; var count = 0; try { let data = JSON.parse(fs.readFileSync('myData.json')); for (var i = 0; i < data.length; i++) { if (data[i].title.includes(req.body.title)) { ans += "<tr>"; count++; ans += "<td>" + data[i].title + "</td>"; ans += "<td>" + data[i].isbn + "</td>"; ans += "<td>" + data[i].shortDescription + "</td>"; ans += "</tr>"; } } ans += "</table>"; console.log("Count = " + count); res.render('form_process_title', { name: 'Form Title', ans: ans }); } catch { res.render('form_process_title', { name: 'Form Title', ans: "Sorry the data does not exist" }); } });
解决方案
问题原因
Handlebars模板引擎默认会对输出内容做HTML转义(防止XSS攻击),所以用{{ans}}输出时,HTML标签会被转成实体字符(比如<变成<),导致浏览器把标签当成普通文本显示,而不是解析成表格。
两种解决方式
方式1:使用Handlebars三重大括号语法
直接在hbs模板里把{{ans}}改成{{{ans}}},三重大括号会告诉Handlebars跳过转义处理,直接输出原始HTML:
修改后的form_process_title.hbs关键代码:
<!-- 把原来的<p>{{ans}}</p>替换成下面的代码 --> {{{ans}}}
注意:如果
ans的内容包含用户输入,必须先做安全校验,避免注入恶意HTML代码引发XSS风险。
方式2:后端用SafeString包装HTML内容
在后端导入Handlebars的SafeString,把拼接好的HTML字符串用它包裹后再传给模板,这样Handlebars就不会转义该内容:
修改后的POST路由代码:
// 先导入SafeString const { SafeString } = require('handlebars'); app.post('/form_route_title', function (req, res, next) { var ans = "<table border = 3>"; ans += "<tr>"; ans += "<td>" + "Title" + "</td>"; ans += "<td>" + "ISBN" + "</td>"; ans += "<td>" + "Description" + "</td>" + "</tr>"; var count = 0; try { let data = JSON.parse(fs.readFileSync('myData.json')); for (var i = 0; i < data.length; i++) { if (data[i].title.includes(req.body.title)) { ans += "<tr>"; count++; ans += "<td>" + data[i].title + "</td>"; ans += "<td>" + data[i].isbn + "</td>"; ans += "<td>" + data[i].shortDescription + "</td>"; ans += "</tr>"; } } ans += "</table>"; console.log("Count = " + count); // 用SafeString包装ans res.render('form_process_title', { name: 'Form Title', ans: new SafeString(ans) }); } catch { // 错误提示也可以用SafeString包装(纯文本不包装也没问题) res.render('form_process_title', { name: 'Form Title', ans: new SafeString("Sorry the data does not exist") }); } });
这种方式适合需要在后端统一处理安全校验的场景,确保传入模板的HTML内容是可信的。
内容的提问来源于stack exchange,提问作者user9115947
相关产品推荐
相关产品推荐

