SPA单页面应用优化SEO
1.SSR服务端渲染
将组件或页面通过服务器生成html,再返回给浏览器,如nuxt.js或
vue-server-renderer
const Vue = require('vue');
const server = require('express')();
const renderer = require('vue-server-renderer').createRenderer();
const vueApp = new Vue({
data() {
return {
url: 'http://localhost:8080'
}
},
template: `<div>访问的URL是: {{ url }}</div>`
});
server.get('*', (req, res) => {
const context = {
url: req.url
};
renderer.renderToString(vueApp, context, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error');
return;
}
res.end(`
<!DOCTYPE html>
<html lang="en">
<head><title>Hello</title></head>
<body>${html}</body>
</html>
`);
});
});
server.listen(8080);
2.静态化
目前主流的静态化主要有两种:
(1)通过程序将动态页面抓取并保存为静态页面,这样的页面的实际存在于服务器的硬盘中。
假设我们有一个简单的Node.js应用,它使用Express框架来处理路由,并使用Puppeteer来抓取页面并保存为静态HTML。
const express = require('express');
const puppeteer = require('puppeteer');
const fs = require('fs');
const app = express();
app.get('/generate-static', async (req, res) => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://localhost:3000/page2', {waitUntil: 'networkidle2'});
const content = await page.content();
await browser.close();
fs.writeFile('static/page2.html', content, (err) => {
if (err) {
return res.status(500).send('Error saving static file');
}
res.send('Static file generated successfully');
});
});
app.get('/page2', (req, res) => {
res.send('<html><body><h1>Page 2 Content</h1></body></html>');
});
app.use(express.static('static'));
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
(2)通过WEB服务器的 URL Rewrite
的方式,它的原理是通过URL重写将静态URL映射到动态处理逻辑,最终返回的是静态内容;
首先,假设我们有一个简单的Node.js应用,提供动态内容:
const express = require('express');
const app = express();
app.get('/dynamic-page2', (req, res) => {
res.send('<html><body><h1>Dynamic Page 2 Content</h1></body></html>');
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
配置Nginx以实现URL重写,当用户访问http://example.com/page2
时,Nginx会将请求重写为/dynamic-page2
,然后代理到运行在localhost:3000
的Express应用。尽管URL看起来是静态的,但实际上返回的是动态生成的内容。
server {
listen 80;
server_name example.com;
location /page2 {
rewrite ^/page2$ /dynamic-page2 break;
proxy_pass http://localhost:3000;
}
location / {
proxy_pass http://localhost:3000;
}
}
3.针对爬虫处理
通过检查请求头中的 User-Agent
来判断请求是否来自爬虫,如果是爬虫请求,则使用 Puppeteer 生成页面;
const express = require('express');
const puppeteer = require('puppeteer');
const app = express();
const PORT = 3000;
// 中间件:检查用户代理是否为爬虫
const isCrawler = (req) => {
const userAgent = req.headers['user-agent'];
return /Googlebot|Bingbot|Baidu|Tencent|Sogou/.test(userAgent);
};
// 路由处理
app.get('/', async (req, res) => {
if (isCrawler(req)) {
// 如果是爬虫请求,则使用 Puppeteer 生成页面
const browser = await puppeteer.launch();
const page = await browser.newPage();
// 访问需要爬取的 URL
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
// 获取生成的 HTML
const content = await page.content();
// 关闭浏览器
await browser.close();
// 返回爬虫请求的 HTML
res.send(content);
} else {
// 正常用户的请求可以返回一个简单的提示
res.send('<h1>欢迎访问我们的网站!</h1>');
}
});
// 启动服务器
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}`);
});