This commit is contained in:
黄心宇 2023-09-14 15:54:29 +08:00
parent 8f338dfeb6
commit e76ff153f8
6 changed files with 2495 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
/node_modules
/.env.local
/.umirc.local.ts
/config/config.local.ts
/src/.umi
/src/.umi-production
/src/.umi-test
/dist
.swc

34
index.js Normal file
View File

@ -0,0 +1,34 @@
import request from 'request';
import express from 'express';
import ssr from './ssr.js';
const app = express()
const port = 3000
const host = 'https://www.gitlink.org.cn';
app.get('/api/*', async (req, res) => {
request(`${host}${req.url}`).pipe(res);
});
app.get('/react/build/*', async (req, res) => {
request(`${host}${req.url}`).pipe(res);
});
app.get('/images/*', async (req, res) => {
request(`${host}${req.url}`).pipe(res);
});
app.get('/system/lets/*', async (req, res) => {
request(`${host}${req.url}`).pipe(res);
});
app.get('*', async (req, res) => {
const {html, ttRenderMs} = await ssr(`${host}${req.originalUrl}`);
res.set('Server-Timing', `Prerender;dur=${ttRenderMs};desc="Headless render time (ms)"`);
return res.status(200).send(html); // Serve prerendered page as response.
});
app.listen(port, () => {
console.log(`app listening on port ${port}`)
})

2370
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "seotest",
"version": "1.0.0",
"description": "seotest",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bluebird": "^3.7.2",
"express": "^4.18.2",
"puppeteer": "^21.2.0",
"redis": "^4.6.8",
"request": "^2.88.2"
},
"type": "module"
}

23
redis/index.js Normal file
View File

@ -0,0 +1,23 @@
import { createClient } from 'redis';
const client = createClient({
url: 'redis://127.0.0.1:6379',
retry_strategy: function(options) {
if (options.error && options.error.code === "ECONNREFUSED") {
return new Error("The server refused the connection");
}
if (options.total_retry_time > 1000 * 60 * 60) {
return new Error("Retry time exhausted");
}
if (options.attempt > 10) {
return undefined;
}
return Math.min(options.attempt * 100, 3000);
},
});
client.on('error', err => console.log('Redis Client Error', err));
await client.connect();
export default client

40
ssr.js Normal file
View File

@ -0,0 +1,40 @@
import puppeteer from 'puppeteer';
import redisClient from './redis/index.js';
async function ssr(url) {
const REDIS_KEY = `ssr:${url}`;
const CACHE_TIME = 600; // 10 分钟缓存
const CACHE_HTML = await redisClient.get(REDIS_KEY);
if (CACHE_HTML) {
return { html: CACHE_HTML, ttRenderMs: 0 };
}
const start = Date.now();
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
headless: 'new'
});
const page = await browser.newPage();
try {
// networkidle0 waits for the network to be idle (no requests for 500ms).
await page.goto(url, {waitUntil: 'networkidle0'});
await page.waitForSelector('#root', { timeout: 0 }); // ensure #posts exists in the DOM.
} catch (err) {
console.error(err);
throw new Error('page.goto/waitForSelector timed out.');
}
const html = await page.content(); // serialized HTML of page DOM.
await browser.close();
const ttRenderMs = Date.now() - start;
console.info(`Puppeteer rendered page: ${url} in: ${ttRenderMs}ms`);
redisClient.set(REDIS_KEY, html, 'EX', CACHE_TIME); // cache rendered page.
return {html, ttRenderMs};
}
export {ssr as default};