mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-05-07 14:16:25 +02:00
fix: #9580, proper 404 when ajaxifying
This commit is contained in:
@@ -7,6 +7,7 @@ const validator = require('validator');
|
|||||||
const meta = require('../meta');
|
const meta = require('../meta');
|
||||||
const plugins = require('../plugins');
|
const plugins = require('../plugins');
|
||||||
const middleware = require('../middleware');
|
const middleware = require('../middleware');
|
||||||
|
const helpers = require('../middleware/helpers');
|
||||||
|
|
||||||
exports.handle404 = function handle404(req, res) {
|
exports.handle404 = function handle404(req, res) {
|
||||||
const relativePath = nconf.get('relative_path');
|
const relativePath = nconf.get('relative_path');
|
||||||
@@ -22,7 +23,13 @@ exports.handle404 = function handle404(req, res) {
|
|||||||
|
|
||||||
if (isClientScript.test(req.url)) {
|
if (isClientScript.test(req.url)) {
|
||||||
res.type('text/javascript').status(404).send('Not Found');
|
res.type('text/javascript').status(404).send('Not Found');
|
||||||
} else if (req.path.startsWith(`${relativePath}/assets/uploads`) || (req.get('accept') && !req.get('accept').includes('text/html')) || req.path === '/favicon.ico') {
|
} else if (
|
||||||
|
!res.locals.isAPI && (
|
||||||
|
req.path.startsWith(`${relativePath}/assets/uploads`) ||
|
||||||
|
(req.get('accept') && !req.get('accept').includes('text/html')) ||
|
||||||
|
req.path === '/favicon.ico'
|
||||||
|
)
|
||||||
|
) {
|
||||||
meta.errors.log404(req.path || '');
|
meta.errors.log404(req.path || '');
|
||||||
res.sendStatus(404);
|
res.sendStatus(404);
|
||||||
} else if (req.accepts('html')) {
|
} else if (req.accepts('html')) {
|
||||||
@@ -41,7 +48,11 @@ exports.send404 = async function (req, res) {
|
|||||||
res.status(404);
|
res.status(404);
|
||||||
const path = String(req.path || '');
|
const path = String(req.path || '');
|
||||||
if (res.locals.isAPI) {
|
if (res.locals.isAPI) {
|
||||||
return res.json({ path: validator.escape(path.replace(/^\/api/, '')), title: '[[global:404.title]]' });
|
return res.json({
|
||||||
|
path: validator.escape(path.replace(/^\/api/, '')),
|
||||||
|
title: '[[global:404.title]]',
|
||||||
|
bodyClass: helpers.buildBodyClass(req, res),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
@@ -49,5 +60,9 @@ exports.send404 = async function (req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await middleware.buildHeaderAsync(req, res);
|
await middleware.buildHeaderAsync(req, res);
|
||||||
await res.render('404', { path: validator.escape(path), title: '[[global:404.title]]' });
|
await res.render('404', {
|
||||||
|
path: validator.escape(path),
|
||||||
|
title: '[[global:404.title]]',
|
||||||
|
bodyClass: helpers.buildBodyClass(req, res),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const winston = require('winston');
|
||||||
|
const validator = require('validator');
|
||||||
|
const slugify = require('../slugify');
|
||||||
|
|
||||||
const helpers = module.exports;
|
const helpers = module.exports;
|
||||||
|
|
||||||
helpers.try = function (middleware) {
|
helpers.try = function (middleware) {
|
||||||
@@ -20,3 +24,34 @@ helpers.try = function (middleware) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
helpers.buildBodyClass = function (req, res, templateData = {}) {
|
||||||
|
const clean = req.path.replace(/^\/api/, '').replace(/^\/|\/$/g, '');
|
||||||
|
const parts = clean.split('/').slice(0, 3);
|
||||||
|
parts.forEach((p, index) => {
|
||||||
|
try {
|
||||||
|
p = slugify(decodeURIComponent(p));
|
||||||
|
} catch (err) {
|
||||||
|
winston.error(err.stack);
|
||||||
|
p = '';
|
||||||
|
}
|
||||||
|
p = validator.escape(String(p));
|
||||||
|
parts[index] = index ? `${parts[0]}-${p}` : `page-${p || 'home'}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (templateData.template && templateData.template.topic) {
|
||||||
|
parts.push(`page-topic-category-${templateData.category.cid}`);
|
||||||
|
parts.push(`page-topic-category-${slugify(templateData.category.name)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(templateData.breadcrumbs)) {
|
||||||
|
templateData.breadcrumbs.forEach((crumb) => {
|
||||||
|
if (crumb && crumb.hasOwnProperty('cid')) {
|
||||||
|
parts.push(`parent-category-${crumb.cid}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.push(`page-status-${res.statusCode}`);
|
||||||
|
return parts.join(' ');
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
const nconf = require('nconf');
|
const nconf = require('nconf');
|
||||||
const validator = require('validator');
|
const validator = require('validator');
|
||||||
const winston = require('winston');
|
|
||||||
|
|
||||||
const plugins = require('../plugins');
|
const plugins = require('../plugins');
|
||||||
const meta = require('../meta');
|
const meta = require('../meta');
|
||||||
const translator = require('../translator');
|
const translator = require('../translator');
|
||||||
const widgets = require('../widgets');
|
const widgets = require('../widgets');
|
||||||
const utils = require('../utils');
|
const utils = require('../utils');
|
||||||
const slugify = require('../slugify');
|
const helpers = require('./helpers');
|
||||||
|
|
||||||
const relative_path = nconf.get('relative_path');
|
const relative_path = nconf.get('relative_path');
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ module.exports = function (middleware) {
|
|||||||
options.relative_path = relative_path;
|
options.relative_path = relative_path;
|
||||||
options.template = { name: template, [template]: true };
|
options.template = { name: template, [template]: true };
|
||||||
options.url = (req.baseUrl + req.path.replace(/^\/api/, ''));
|
options.url = (req.baseUrl + req.path.replace(/^\/api/, ''));
|
||||||
options.bodyClass = buildBodyClass(req, res, options);
|
options.bodyClass = helpers.buildBodyClass(req, res, options);
|
||||||
|
|
||||||
const buildResult = await plugins.hooks.fire(`filter:${template}.build`, { req: req, res: res, templateData: options });
|
const buildResult = await plugins.hooks.fire(`filter:${template}.build`, { req: req, res: res, templateData: options });
|
||||||
if (res.headersSent) {
|
if (res.headersSent) {
|
||||||
@@ -123,34 +123,4 @@ module.exports = function (middleware) {
|
|||||||
const translated = await translator.translate(str, language);
|
const translated = await translator.translate(str, language);
|
||||||
return translator.unescape(translated);
|
return translator.unescape(translated);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildBodyClass(req, res, templateData) {
|
|
||||||
const clean = req.path.replace(/^\/api/, '').replace(/^\/|\/$/g, '');
|
|
||||||
const parts = clean.split('/').slice(0, 3);
|
|
||||||
parts.forEach((p, index) => {
|
|
||||||
try {
|
|
||||||
p = slugify(decodeURIComponent(p));
|
|
||||||
} catch (err) {
|
|
||||||
winston.error(err.stack);
|
|
||||||
p = '';
|
|
||||||
}
|
|
||||||
p = validator.escape(String(p));
|
|
||||||
parts[index] = index ? `${parts[0]}-${p}` : `page-${p || 'home'}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (templateData.template.topic) {
|
|
||||||
parts.push(`page-topic-category-${templateData.category.cid}`);
|
|
||||||
parts.push(`page-topic-category-${slugify(templateData.category.name)}`);
|
|
||||||
}
|
|
||||||
if (templateData.breadcrumbs) {
|
|
||||||
templateData.breadcrumbs.forEach((crumb) => {
|
|
||||||
if (crumb.hasOwnProperty('cid')) {
|
|
||||||
parts.push(`parent-category-${crumb.cid}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
parts.push(`page-status-${res.statusCode}`);
|
|
||||||
return parts.join(' ');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user