You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React应用搭配Express后端:登录/注册等多模块路由实现咨询

Is splitting signIn/signUp/user data modules reasonable, and how to configure Express routes?

Absolutely, splitting your authentication (signIn/signUp) and user data display into separate modules is not just reasonable—it’s a great practice for building maintainable, scalable React + Express apps. Here’s why it makes sense:

  • Separation of concerns: Each module focuses on one specific task (auth vs user data), making your code easier to debug, test, and update. For example, you can tweak sign-up validation logic without touching the user profile display code.
  • Reusability: Auth modules can be reused across different parts of your app (like protecting React routes), while user data modules can be extended to handle profile edits or admin dashboards later.
  • Team collaboration: If you’re working with others, different developers can own different modules without stepping on each other’s toes.

How to configure Express routes for these modules

First, let’s structure your Express app to keep routes organized. We’ll split API routes into dedicated files, then handle React’s static files and SPA fallback properly.

1. Project structure example

your-app/
├── client/          # React app (build output goes here)
├── server/
│   ├── routes/
│   │   ├── auth.js  # signIn/signUp routes
│   │   └── users.js # user data routes
│   ├── middleware/
│   │   └── auth.js  # JWT verification middleware
│   └── app.js       # Main Express server file

2. Create auth routes (server/routes/auth.js)

This file handles user registration and login, with logic for password hashing, input validation, and JWT token issuance (for authenticated requests later):

const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User'); // Assume you have a User Mongoose model

// Sign up route
router.post('/signup', async (req, res) => {
  try {
    const { email, password, username } = req.body;
    
    // Check if user already exists
    const existingUser = await User.findOne({ email });
    if (existingUser) {
      return res.status(400).json({ message: 'User already exists' });
    }

    // Hash password
    const hashedPassword = await bcrypt.hash(password, 10);

    // Create new user
    const newUser = new User({ email, password: hashedPassword, username });
    await newUser.save();

    // Issue JWT
    const token = jwt.sign({ userId: newUser._id }, process.env.JWT_SECRET, { expiresIn: '1d' });
    res.status(201).json({ token, user: { id: newUser._id, email: newUser.email, username: newUser.username } });
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

// Sign in route
router.post('/signin', async (req, res) => {
  try {
    const { email, password } = req.body;
    
    const user = await User.findOne({ email });
    if (!user) {
      return res.status(400).json({ message: 'Invalid credentials' });
    }

    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
      return res.status(400).json({ message: 'Invalid credentials' });
    }

    const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: '1d' });
    res.json({ token, user: { id: user._id, email: user.email, username: user.username } });
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

module.exports = router;

3. Create user data routes (server/routes/users.js)

This file handles fetching user data, protected by an authentication middleware to ensure only logged-in users can access sensitive endpoints:

const express = require('express');
const router = express.Router();
const authMiddleware = require('../middleware/auth'); // Your JWT verification middleware
const User = require('../models/User');

// Get current user's data
router.get('/me', authMiddleware, async (req, res) => {
  try {
    // Fetch user without exposing the password field
    const user = await User.findById(req.userId).select('-password');
    if (!user) {
      return res.status(404).json({ message: 'User not found' });
    }
    res.json(user);
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

// Get user by ID (for public profiles or admin use, adjust permissions as needed)
router.get('/:id', async (req, res) => {
  try {
    const user = await User.findById(req.params.id).select('-password');
    if (!user) {
      return res.status(404).json({ message: 'User not found' });
    }
    res.json(user);
  } catch (err) {
    res.status(500).json({ message: 'Server error' });
  }
});

module.exports = router;

4. Configure main Express server (server/app.js)

Here, we’ll mount the API routes, serve React’s static build files, and handle SPA fallback (return index.html for all non-API requests):

const express = require('express');
const cors = require('cors');
const path = require('path');
const authRoutes = require('./routes/auth');
const userRoutes = require('./routes/users');

const app = express();

// Middleware
app.use(cors()); // Allow cross-origin requests (if React runs on a different port)
app.use(express.json()); // Parse JSON request bodies

// Mount API routes
app.use('/api/auth', authRoutes);
app.use('/api/users', userRoutes);

// Serve React static files (after running `npm run build` in your React app)
app.use(express.static(path.join(__dirname, '../client/build')));

// SPA fallback: return index.html for all non-API requests
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, '../client/build/index.html'));
});

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

5. Key notes for React integration

  • In your React app, create separate service modules (e.g., AuthService.js for signIn/signUp calls, UserService.js for fetching user data) to encapsulate API requests. Example:
    // AuthService.js
    export const signUp = (userData) => {
      return fetch('/api/auth/signup', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(userData)
      }).then(res => res.json());
    };
    
  • Use React Context or state management (like Redux) to store the JWT token and user data, so you can attach the token to authenticated requests (e.g., adding an Authorization: Bearer ${token} header in UserService.js).

内容的提问来源于stack exchange,提问作者Austris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:06:04