0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Optimized link redirects handling

refs https://github.com/TryGhost/Toolbox/issues/515

- The link redirect handled was querying database on every single frontend request causing a significant amount of unnecessary traffic
- The optimization is returning early if the incoming URL does not start with a common "r/" prefix
This commit is contained in:
Naz 2023-02-02 15:01:20 +08:00 committed by Simon Backx
parent 3f5e34f840
commit 32cd3b9433
3 changed files with 49 additions and 6 deletions

View file

@ -23,7 +23,7 @@ module.exports = class LinkRedirectRepository {
*/
async save(linkRedirect) {
const model = await this.#LinkRedirect.add({
// Only store the parthname (no support for variable query strings)
// Only store the pathname (no support for variable query strings)
from: this.stripSubdirectoryFromPath(linkRedirect.from.pathname),
to: linkRedirect.to.href
}, {});

View file

@ -17,6 +17,9 @@ class LinkRedirectsService {
/** @type URL */
#baseURL;
/** @type String */
#redirectURLPrefix = 'r/';
/**
* @param {object} deps
* @param {ILinkRedirectRepository} deps.linkRedirectRepository
@ -43,7 +46,7 @@ class LinkRedirectsService {
let url;
while (!url || await this.#linkRedirectRepository.getByURL(url)) {
const slug = crypto.randomBytes(4).toString('hex');
url = new URL(`r/${slug}`, this.#baseURL);
url = new URL(`${this.#redirectURLPrefix}${slug}`, this.#baseURL);
}
return url;
}
@ -82,6 +85,12 @@ class LinkRedirectsService {
* @returns {Promise<void>}
*/
async handleRequest(req, res, next) {
// skip handling if original url doesn't match the prefix
const fullURLWithRedirectPrefix = `${this.#baseURL.pathname}${this.#redirectURLPrefix}`;
if (!req.originalUrl.startsWith(fullURLWithRedirectPrefix)) {
return next();
}
const url = new URL(req.originalUrl, this.#baseURL);
const link = await this.#linkRedirectRepository.getByURL(url);

View file

@ -1,4 +1,4 @@
const LinkRedirectsService = require('../lib/LinkRedirectsService');
const {LinkRedirectsService} = require('../index');
const assert = require('assert');
const sinon = require('sinon');
const crypto = require('crypto');
@ -73,7 +73,7 @@ describe('LinkRedirectsService', function () {
it('redirects if found', async function () {
const linkRedirectRepository = {
getByURL: (url) => {
if (url.toString() === 'https://localhost:2368/a') {
if (url.toString() === 'https://localhost:2368/r/a') {
return Promise.resolve({
to: new URL('https://localhost:2368/b')
});
@ -88,7 +88,7 @@ describe('LinkRedirectsService', function () {
}
});
const req = {
originalUrl: '/a'
originalUrl: '/r/a'
};
const res = {
redirect: sinon.fake(),
@ -111,12 +111,46 @@ describe('LinkRedirectsService', function () {
}
});
const req = {
url: '/a'
originalUrl: 'r/a'
};
const res = {};
const next = sinon.fake();
await instance.handleRequest(req, res, next);
assert.equal(next.callCount, 1);
});
it('does not redirect if url does not contain a redirect prefix on site with no subdir', async function () {
const instance = new LinkRedirectsService({
config: {
baseURL: new URL('https://localhost:2368/')
}
});
const req = {
originalUrl: 'no_r/prefix'
};
const res = {};
const next = sinon.fake();
await instance.handleRequest(req, res, next);
assert.equal(next.callCount, 1);
});
it('does not redirect if url does not contain a redirect prefix on site with subdir', async function () {
const instance = new LinkRedirectsService({
config: {
baseURL: new URL('https://localhost:2368/blog')
}
});
const req = {
originalUrl: 'blog/no_r/prefix'
};
const res = {};
const next = sinon.fake();
await instance.handleRequest(req, res, next);
assert.equal(next.callCount, 1);
});
});
});