阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > Express与前端框架的集成

Express与前端框架的集成

作者:陈川 阅读数:30053人阅读 分类: Node.js

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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌