如何在expressjs中使用Nodejs检测响应类型,如果是html则设置响应头?
如何在expressjs中使用Nodejs检测响应类型,如果是html则设置响应头?
现在我想实现一个需求:如果响应类型是 text/html,那么我需要统一设置一些 HTTP 响应头比如 Cache-Control、X-Frame-Options等,当然最好通过中间件的形式来实现,我总不能在每一次响应 html 之前都重复这一段代码:
res.set( {
'Cache-Control' : 'public, max-age=60' ,
'X-Frame-Options' : 'DENY'
} );
但如果我直接把这段代码写成一个中间件的话,其它类型比如css
、js
的缓存时间也会被覆盖掉;
然后我又想到了打补丁的方式:
var render = res.render;
res.render = function () {
res.set( {
'Cache-Control' : 'public, max-age=60' ,
'X-Frame-Options' : 'DENY'
} );
render.apply( res , arguments );
};
那么问题又来了,如果按照这样的思路,我还需要为其它类似方法如res.sendFile()
、res.send()
都打一个补丁,但我找不到某种方法来判断此次 res 是否会返回一个 html。
最后我想来想去只有这么做了:
设计 URL 的时候遵循一定的规则,比如加后缀 .json
表示这个网址会返回 json ,加后缀 .html
表示这个网址会返回 html 等等。这样我就可以在一个中间件里面通过后缀来判断该怎么控制了。这估计是最后的王牌了。
但难道没有更好更通用的方法了吗?求助= =
要在Express.js中检测响应类型,并且只在响应类型为 text/html
时设置特定的HTTP响应头,可以通过创建一个中间件来实现。这种方法避免了对每个响应方法(如 res.render
, res.sendFile
, res.send
)进行逐一修改或打补丁。
示例代码
首先,创建一个中间件函数,该函数检查请求的Accept头部是否包含 text/html
,并根据条件设置响应头:
const express = require('express');
const app = express();
// 定义中间件
app.use((req, res, next) => {
// 检查请求头中的Accept字段是否包含text/html
const acceptsHtml = req.accepts('html') === 'html';
if (acceptsHtml) {
// 设置响应头
res.set({
'Cache-Control': 'public, max-age=60',
'X-Frame-Options': 'DENY'
});
}
// 继续处理下一个中间件或路由
next();
});
// 示例路由
app.get('/', (req, res) => {
res.send('<h1>Hello, World!</h1>');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
解释
-
中间件:我们创建了一个中间件函数,它接受三个参数:
req
(请求对象)、res
(响应对象)和next
(用于调用下一个中间件或路由处理程序的函数)。 -
检查Accept头部:
req.accepts('html')
方法用于检查请求头中的Accept
字段是否包含text/html
。如果请求确实期望HTML内容,该方法将返回'html'
。 -
设置响应头:如果请求期望HTML内容,我们在响应头中设置所需的缓存控制和X-Frame-Options值。
-
继续处理:
next()
被调用以确保请求可以继续传递到下一个中间件或路由处理程序。
这种方法避免了对每个响应方法进行单独修改,同时能够灵活地处理不同类型的内容。
建立一个router再使用你的中间件不行么? 或者把中间件在使用static以后再use不行么?
你可以通过创建一个自定义中间件来解决这个问题。该中间件可以检查请求的 Accept 头或响应的内容类型,然后根据这些信息设置响应头。这里提供了一个示例,展示了如何实现这一功能:
const express = require('express');
const app = express();
app.use((req, res, next) => {
const originalSend = res.send;
const originalJson = res.json;
res.send = (body) => {
if (typeof body === 'string' && body.includes('<html')) {
// HTML响应头设置
res.set({
'Cache-Control': 'public, max-age=60',
'X-Frame-Options': 'DENY'
});
}
return originalSend.call(this, body);
};
res.json = (obj) => {
return originalJson.call(this, obj);
};
next();
});
// 示例路由
app.get('/', (req, res) => {
res.send('<html><body>Hello World!</body></html>');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
在这个例子中,我们创建了一个中间件,在调用 res.send()
时检查响应体是否包含 <html
标签。如果包含,则设置所需的响应头。请注意,这可能不是最通用的方法,但它可以在大多数情况下工作。对于 JSON 响应,我们不需要更改行为,因此我们只是简单地将 res.json()
方法替换回其原始值。
如果你想更精确地检测响应类型,你可能需要更深入地了解 Express.js 如何处理路由和响应。但上述示例应该能满足你的基本需求。