如题,项目前端是nuxt2做的,现在遇到如下问题
当通过非正常编码编码后的url 访问的时候, pm2日志中报错 "URI malformed"
探究了一下,错误是因为 /node_moduels/@nuxt/server/dist/server.js 文件中的
const nuxtMiddleware = ({ options, nuxt, renderRoute, resources }) => async function nuxtMiddleware (req, res, next) {
// Get context
const context = utils.getContext(req, res);
try {
const url = decodeURI(req.url); //这里
res.statusCode = 200;
const result = await renderRoute(url, context);
// If result is falsy, call renderLoading
if (!result) {
await nuxt.callHook('server:nuxt:renderLoading', req, res);
return
}
await nuxt.callHook('render:route', url, result, context);
const {
html,
cspScriptSrcHashes,
error,
redirected,
preloadFiles
} = result;
if (redirected && context.target !== utils.TARGETS.static) {
await nuxt.callHook('render:routeDone', url, result, context);
return html
}
if (error) {
res.statusCode = context.nuxt.error.statusCode || 500;
}
if (options.render.csp && cspScriptSrcHashes) {
const { allowedSources, policies } = options.render.csp;
const isReportOnly = !!options.render.csp.reportOnly;
const cspHeader = isReportOnly ? 'Content-Security-Policy-Report-Only' : 'Content-Security-Policy';
res.setHeader(cspHeader, getCspString({ cspScriptSrcHashes, allowedSources, policies, isReportOnly }));
}
// Add ETag header
if (!error && options.render.etag) {
const { hash } = options.render.etag;
const etag = hash ? hash(html, options.render.etag) : generateETag__default['default'](html, options.render.etag);
if (fresh__default['default'](req.headers, { etag })) {
res.statusCode = 304;
await nuxt.callHook('render:beforeResponse', url, result, context);
res.end();
await nuxt.callHook('render:routeDone', url, result, context);
return
}
res.setHeader('ETag', etag);
}
// HTTP2 push headers for preload assets
if (!error && options.render.http2.push) {
// Parse resourceHints to extract HTTP.2 prefetch/push headers
// https://w3c.github.io/preload/#server-push-http-2
const { shouldPush, pushAssets } = options.render.http2;
const { publicPath } = resources.clientManifest;
const links = pushAssets
? pushAssets(req, res, publicPath, preloadFiles)
: defaultPushAssets(preloadFiles, shouldPush, publicPath, options);
// Pass with single Link header
// https://blog.cloudflare.com/http-2-server-push-with-multiple-assets-per-link-header
// https://www.w3.org/Protocols/9707-link-header.html
if (links.length > 0) {
res.setHeader('Link', links.join(', '));
}
}
// Send response
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.setHeader('Accept-Ranges', 'none'); // #3870
res.setHeader('Content-Length', Buffer.byteLength(html));
await nuxt.callHook('render:beforeResponse', url, result, context);
res.end(html, 'utf8');
await nuxt.callHook('render:routeDone', url, result, context);
return html
} catch (err) {
if (context && context.redirected) {
consola__default['default'].error(err);
return err
}
if (err.name === 'URIError') { //这里
err.statusCode = 400;
}
next(err);
}
};
其中
const url = decodeURI(req.url);
对url无法进行解析,导致的.
需求是想在遇到"URI malformed"错误的时候,直接跳首页,目前采用了两种做法解决
第一种:
在nuxt.config.js文件中,增加 serverMiddleware 配置项
serverMiddleware: [
(req, res, next) => {
// 自定义中间件逻辑...
try {
//尝试解析url
decodeURIComponent(req.url)
//往下继续执行
next();
} catch {
//解析错误就跳转
res.writeHead(302, {
Location: '/'
});
res.end();
}
}
],
这样可以解决,但是无法阻止server.js 文件会对url再次进行解析,这样比较消耗资源
第二种:
直接修改 /node_moduels/@nuxt/server/dist/server.js 文件
在
if (err.name === 'URIError') {
err.statusCode = 400;
}
中加入:
if (err.name === 'URIError') {
err.statusCode = 400;
//新加
res.writeHead(302, { Location: '/' })
//新加
return res.end()
}
这样也能起到效果,但是这样就直接修改了核心代码
第三种:
使用nuxt.config.js 中的hook,示例如下
hooks: {
render: {
errorMiddleware(app) {
app.use((error, req, res, next) => {
res.writeHead(302, {
Location: '/',
})
res.end()
})
},
},
这样也可以,似乎更恰当一些
但是对于负载来说, 是重定向到首页好,还是直接返回错误页,还是直接返回错误提示更好呢?