Express与前端框架的集成
Express与前端框架的集成方式
Express作为Node.js的轻量级Web框架,常与React、Vue或Angular等前端框架配合使用。集成方式主要分为两种:服务端渲染(SSR)和前后端分离开发模式。SSR通过模板引擎(如EJS、Pug)或框架专用方案(如Next.js)实现,而分离模式下Express仅提供API接口。
服务端渲染(SSR)集成
使用模板引擎
Express原生支持模板引擎,例如用EJS渲染动态页面:
// app.js
const express = require('express');
const app = express();
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('index', { title: 'Express + EJS' });
});
app.listen(3000);
对应的EJS模板文件:
<!-- views/index.ejs -->
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
</body>
</html>
与Next.js集成
对于React项目,可通过自定义Express服务器扩展Next.js:
// server.js
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.get('/custom-route', (req, res) => {
return app.render(req, res, '/custom-page', req.query);
});
server.all('*', (req, res) => {
return handle(req, res);
});
server.listen(3000);
});
前后端分离模式
REST API基础配置
Express作为纯后端服务时,需配置CORS和JSON解析:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
app.get('/api/data', (req, res) => {
res.json({ items: [{ id: 1, name: 'Item 1' }] });
});
app.listen(3001);
前端通过fetch调用示例:
fetch('http://localhost:3001/api/data')
.then(response => response.json())
.then(data => console.log(data));
文件上传集成
结合multer处理文件上传:
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file);
res.status(200).send('Uploaded');
});
前端上传组件示例(React):
function Uploader() {
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append('file', e.target.files[0]);
fetch('/upload', {
method: 'POST',
body: formData
});
};
return <input type="file" onChange={handleSubmit} />;
}
实时通信方案
WebSocket集成
使用ws库创建实时服务:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (message) => {
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
});
});
前端连接示例:
const socket = new WebSocket('ws://localhost:8080');
socket.addEventListener('message', (event) => {
console.log('Received:', event.data);
});
Socket.IO深度集成
Express与Socket.IO结合实现命名空间:
const io = require('socket.io')(server);
io.of('/chat').on('connection', (socket) => {
socket.on('new-message', (msg) => {
io.of('/chat').emit('message', msg);
});
});
对应的React组件:
useEffect(() => {
const socket = io('http://localhost:3000/chat');
socket.on('message', (msg) => {
setMessages(prev => [...prev, msg]);
});
return () => socket.disconnect();
}, []);
静态资源托管
生产环境部署配置
Express托管前端构建产物:
const path = require('path');
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
开发环境代理设置
配置http-proxy-middleware解决跨域:
const { createProxyMiddleware } = require('http-proxy-middleware');
app.use('/api', createProxyMiddleware({
target: 'http://localhost:3001',
changeOrigin: true
}));
对应Vue配置(vue.config.js):
module.exports = {
devServer: {
proxy: 'http://localhost:3000'
}
}
认证集成方案
JWT认证实现
Express生成JWT令牌:
const jwt = require('jsonwebtoken');
app.post('/login', (req, res) => {
const token = jwt.sign({ userId: 123 }, 'secret', { expiresIn: '1h' });
res.json({ token });
});
前端axios拦截器配置:
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
OAuth2.0集成
使用Passport实现GitHub认证:
const passport = require('passport');
const GitHubStrategy = require('passport-github').Strategy;
passport.use(new GitHubStrategy({
clientID: GITHUB_CLIENT_ID,
clientSecret: GITHUB_CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/github/callback"
}, (accessToken, refreshToken, profile, done) => {
return done(null, profile);
}));
app.get('/auth/github', passport.authenticate('github'));
app.get('/auth/github/callback',
passport.authenticate('github', { failureRedirect: '/login' }),
(req, res) => res.redirect('/')
);
性能优化策略
服务端缓存配置
启用Redis缓存API响应:
const redis = require('redis');
const client = redis.createClient();
function cacheMiddleware(req, res, next) {
const key = req.originalUrl;
client.get(key, (err, data) => {
if (data) return res.json(JSON.parse(data));
next();
});
}
app.get('/heavy-route', cacheMiddleware, (req, res) => {
// 耗时操作
const result = { data: '...' };
client.setex(req.originalUrl, 3600, JSON.stringify(result));
res.json(result);
});
静态资源压缩
启用gzip压缩:
const compression = require('compression');
app.use(compression({ level: 6 }));
错误处理机制
统一错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
error: process.env.NODE_ENV === 'development' ?
err.message : 'Internal Error'
});
});
前端错误捕获
React错误边界示例:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
fetch('/api/log-error', {
method: 'POST',
body: JSON.stringify({ error, info })
});
}
render() {
return this.state.hasError
? <div>Error occurred</div>
: this.props.children;
}
}
微前端架构支持
模块联邦集成
通过Express提供模块联邦所需的远程入口:
app.get('/remoteEntry.js', (req, res) => {
res.sendFile(path.resolve(__dirname, 'dist/remoteEntry.js'));
});
Webpack配置示例:
// webpack.config.js
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js'
}
})
]
}
测试策略实施
接口测试方案
使用Jest测试Express路由:
const request = require('supertest');
const app = require('../app');
describe('GET /api/users', () => {
it('responds with JSON', async () => {
const response = await request(app)
.get('/api/users')
.expect('Content-Type', /json/)
.expect(200);
expect(response.body).toHaveProperty('users');
});
});
E2E测试配置
结合Cypress进行全栈测试:
// cypress/integration/api.spec.js
describe('API Tests', () => {
it('creates new item', () => {
cy.request('POST', '/api/items', { name: 'Test' })
.its('body')
.should('include', { id: 1 });
});
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:常用插件与扩展库介绍