【Node.js】全栈开发实践

news2025/7/15 4:09:20

在这里插入图片描述

个人主页:Guiat
归属专栏:node.js

在这里插入图片描述

文章目录

  • 1. Node.js 全栈开发概述
    • 1.1 全栈开发的优势
    • 1.2 Node.js 全栈开发技术栈
  • 2. 开发环境搭建
    • 2.1 Node.js 和 npm 安装
    • 2.2 开发工具安装
    • 2.3 版本控制设置
    • 2.4 项目初始化流程
  • 3. 后端开发 (Node.js)
    • 3.1 Express 框架基础
    • 3.2 RESTful API 设计
    • 3.3 中间件开发
    • 3.4 数据库集成
    • 3.5 身份验证和授权
    • 3.6 后端架构
  • 4. 前端开发
    • 4.1 React 基础
    • 4.2 状态管理 (Redux)
    • 4.3 API 请求处理
    • 4.4 前端路由 (React Router)
    • 4.5 前端架构
  • 5. 全栈集成
    • 5.1 前后端通信
    • 5.2 身份验证流程
    • 5.3 完整的全栈应用架构
  • 6. 数据建模与持久化
    • 6.1 MongoDB 数据模型
    • 6.2 MySQL 数据建模
    • 6.3 数据关系建模
  • 7. API 开发与设计模式
    • 7.1 模块化路由
    • 7.2 控制器模式
    • 7.3 服务层模式
    • 7.4 错误处理模式
  • 8. 安全性与性能优化
    • 8.1 安全最佳实践
    • 8.2 性能优化技术
    • 8.3 日志系统
  • 9. 部署与 DevOps
    • 9.1 Docker 容器化
    • 9.2 CI/CD 流水线
    • 9.3 部署流程

正文

1. Node.js 全栈开发概述

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,使开发者能够使用 JavaScript 进行服务器端编程。全栈开发指的是同时处理前端和后端的开发工作。

1.1 全栈开发的优势

  • 使用统一的语言(JavaScript)开发前后端
  • 减少技术栈上下文切换成本
  • 提高开发效率和代码复用性
  • 便于小团队快速构建完整应用
  • 简化部署和维护流程

1.2 Node.js 全栈开发技术栈

Node.js全栈技术栈
前端技术
后端技术
数据库技术
开发工具
部署技术
React/Vue/Angular
HTML/CSS
TypeScript
Express/Koa/NestJS
GraphQL
RESTful API
MongoDB
MySQL/PostgreSQL
Redis
npm/Yarn
Webpack/Vite
Git
Docker
AWS/Azure/GCP
CI/CD管道

2. 开发环境搭建

2.1 Node.js 和 npm 安装

Node.js 是全栈开发的基础环境,npm 是其包管理工具。

# 安装 Node.js 和 npm (macOS)
brew install node

# 安装 Node.js 和 npm (Ubuntu)
sudo apt update
sudo apt install nodejs npm

# 安装 Node.js 和 npm (Windows)
# 从 https://nodejs.org 下载安装程序

# 验证安装
node --version
npm --version

2.2 开发工具安装

良好的开发工具可以提高开发效率:

# 安装常用全局工具
npm install -g nodemon # 自动重启服务器
npm install -g ts-node # TypeScript 执行环境
npm install -g create-react-app # React 项目生成器
npm install -g @vue/cli # Vue 项目生成器
npm install -g prettier # 代码格式化工具

2.3 版本控制设置

Git 是最流行的版本控制系统:

# 初始化 Git 仓库
git init

# 创建 .gitignore 文件
echo "node_modules/\n.env\n.DS_Store\ndist/\nbuild/" > .gitignore

# 配置用户信息
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

2.4 项目初始化流程

项目初始化
创建项目目录
初始化npm
创建基本目录结构
安装依赖
配置环境变量
编写启动脚本
初始化Git仓库

3. 后端开发 (Node.js)

3.1 Express 框架基础

Express 是 Node.js 最流行的 Web 应用框架之一。

// 基本 Express 服务器
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 路由
app.get('/', (req, res) => {
  res.send('Hello World!');
});

// 启动服务器
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

3.2 RESTful API 设计

RESTful API 是一种软件架构风格,用于设计网络应用。

// 用户资源的 RESTful API
const express = require('express');
const router = express.Router();

// 获取所有用户
router.get('/users', (req, res) => {
  // 实现获取所有用户的逻辑
  res.json({ users: [] });
});

// 获取单个用户
router.get('/users/:id', (req, res) => {
  const userId = req.params.id;
  // 实现获取单个用户的逻辑
  res.json({ user: { id: userId } });
});

// 创建用户
router.post('/users', (req, res) => {
  const userData = req.body;
  // 实现创建用户的逻辑
  res.status(201).json({ user: userData });
});

// 更新用户
router.put('/users/:id', (req, res) => {
  const userId = req.params.id;
  const userData = req.body;
  // 实现更新用户的逻辑
  res.json({ user: { id: userId, ...userData } });
});

// 删除用户
router.delete('/users/:id', (req, res) => {
  const userId = req.params.id;
  // 实现删除用户的逻辑
  res.status(204).end();
});

module.exports = router;

3.3 中间件开发

中间件是 Express 中处理请求和响应的功能模块。

// 认证中间件
const jwt = require('jsonwebtoken');

const authMiddleware = (req, res, next) => {
  const token = req.header('Authorization')?.replace('Bearer ', '');
  
  if (!token) {
    return res.status(401).json({ message: '未提供访问令牌' });
  }
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (error) {
    return res.status(401).json({ message: '无效的访问令牌' });
  }
};

// 错误处理中间件
const errorHandlerMiddleware = (err, req, res, next) => {
  console.error(err.stack);
  
  // 自定义错误响应
  if (err.name === 'ValidationError') {
    return res.status(400).json({ message: err.message });
  }
  
  res.status(500).json({ message: '服务器内部错误' });
};

module.exports = { authMiddleware, errorHandlerMiddleware };

3.4 数据库集成

Node.js 可以与各种数据库集成。

// MongoDB 集成 (使用 Mongoose)
const mongoose = require('mongoose');

// 连接 MongoDB
mongoose.connect(process.env.MONGODB_URI, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
.then(() => console.log('MongoDB 连接成功'))
.catch((err) => console.error('MongoDB 连接失败:', err));

// 定义用户模型
const userSchema = new mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true,
    trim: true,
  },
  email: {
    type: String,
    required: true,
    unique: true,
    trim: true,
    lowercase: true,
  },
  password: {
    type: String,
    required: true,
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

const User = mongoose.model('User', userSchema);

module.exports = User;
// MySQL 集成 (使用 mysql2)
const mysql = require('mysql2/promise');

// 创建连接池
const pool = mysql.createPool({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0,
});

// 用户数据访问对象
const UserDAO = {
  // 获取所有用户
  async getAllUsers() {
    const [rows] = await pool.query('SELECT * FROM users');
    return rows;
  },
  
  // 通过 ID 获取用户
  async getUserById(id) {
    const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
    return rows[0];
  },
  
  // 创建用户
  async createUser(user) {
    const { username, email, password } = user;
    const [result] = await pool.query(
      'INSERT INTO users (username, email, password) VALUES (?, ?, ?)',
      [username, email, password]
    );
    return { id: result.insertId, ...user };
  },
};

module.exports = UserDAO;

3.5 身份验证和授权

// JWT 身份验证实现
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const User = require('../models/User');

const authController = {
  // 用户注册
  async register(req, res) {
    try {
      const { username, email, password } = req.body;
      
      // 检查是否已存在用户
      const existingUser = await User.findOne({ $or: [{ username }, { email }] });
      if (existingUser) {
        return res.status(400).json({ message: '用户名或邮箱已被使用' });
      }
      
      // 哈希密码
      const hashedPassword = await bcrypt.hash(password, 10);
      
      // 创建新用户
      const newUser = new User({
        username,
        email,
        password: hashedPassword,
      });
      
      await newUser.save();
      
      // 生成 JWT
      const token = jwt.sign(
        { userId: newUser._id, username: newUser.username },
        process.env.JWT_SECRET,
        { expiresIn: '1h' }
      );
      
      res.status(201).json({ user: newUser, token });
    } catch (error) {
      res.status(500).json({ message: '注册失败', error: error.message });
    }
  },
  
  // 用户登录
  async login(req, res) {
    try {
      const { username, password } = req.body;
      
      // 查找用户
      const user = await User.findOne({ username });
      if (!user) {
        return res.status(401).json({ message: '用户名或密码错误' });
      }
      
      // 验证密码
      const isPasswordValid = await bcrypt.compare(password, user.password);
      if (!isPasswordValid) {
        return res.status(401).json({ message: '用户名或密码错误' });
      }
      
      // 生成 JWT
      const token = jwt.sign(
        { userId: user._id, username: user.username },
        process.env.JWT_SECRET,
        { expiresIn: '1h' }
      );
      
      res.json({ user, token });
    } catch (error) {
      res.status(500).json({ message: '登录失败', error: error.message });
    }
  },
};

module.exports = authController;

3.6 后端架构

Express 应用
路由层
中间件层
控制器层
数据访问层
服务层
API 路由
Web 路由
认证路由
身份验证
日志记录
错误处理
CORS
用户控制器
产品控制器
订单控制器
用户仓库
产品仓库
订单仓库
认证服务
电子邮件服务
支付服务
数据库

4. 前端开发

4.1 React 基础

React 是一个用于构建用户界面的 JavaScript 库。

// 创建 React 应用
npx create-react-app my-app
cd my-app
npm start

// 简单的 React 组件
import React from 'react';

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

export default Welcome;

4.2 状态管理 (Redux)

Redux 是一个 JavaScript 状态容器,提供可预测的状态管理。

// Redux store 配置
import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import { userReducer } from './reducers/userReducer';
import { productReducer } from './reducers/productReducer';

// 合并 reducers
const rootReducer = combineReducers({
  user: userReducer,
  products: productReducer,
});

// 创建 store
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);

export default store;

// 用户 reducer
const initialState = {
  currentUser: null,
  isLoading: false,
  error: null,
};

export const userReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'LOGIN_REQUEST':
      return { ...state, isLoading: true, error: null };
    case 'LOGIN_SUCCESS':
      return { ...state, isLoading: false, currentUser: action.payload };
    case 'LOGIN_FAILURE':
      return { ...state, isLoading: false, error: action.payload };
    case 'LOGOUT':
      return { ...state, currentUser: null };
    default:
      return state;
  }
};

// 用户 actions
export const loginUser = (credentials) => {
  return async (dispatch) => {
    try {
      dispatch({ type: 'LOGIN_REQUEST' });
      
      const response = await fetch('/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(credentials),
      });
      
      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.message);
      }
      
      const data = await response.json();
      localStorage.setItem('token', data.token);
      
      dispatch({ type: 'LOGIN_SUCCESS', payload: data.user });
    } catch (error) {
      dispatch({ type: 'LOGIN_FAILURE', payload: error.message });
    }
  };
};

4.3 API 请求处理

使用 Axios 或 Fetch API 处理 HTTP 请求。

// 使用 Axios 的 API 服务
import axios from 'axios';

// 创建 axios 实例
const apiClient = axios.create({
  baseURL: process.env.REACT_APP_API_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

// 请求拦截器添加认证 token
apiClient.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 响应拦截器处理错误
apiClient.interceptors.response.use(
  (response) => response,
  (error) => {
    // 处理 401 错误
    if (error.response && error.response.status === 401) {
      // 清除本地存储并重定向到登录页
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

// 用户相关 API 调用
export const userService = {
  login: (credentials) => apiClient.post('/auth/login', credentials),
  register: (userData) => apiClient.post('/auth/register', userData),
  getCurrentUser: () => apiClient.get('/users/me'),
  updateProfile: (userData) => apiClient.put('/users/me', userData),
};

// 产品相关 API 调用
export const productService = {
  getProducts: (params) => apiClient.get('/products', { params }),
  getProductById: (id) => apiClient.get(`/products/${id}`),
  createProduct: (productData) => apiClient.post('/products', productData),
  updateProduct: (id, productData) => apiClient.put(`/products/${id}`, productData),
  deleteProduct: (id) => apiClient.delete(`/products/${id}`),
};

export default apiClient;

4.4 前端路由 (React Router)

React Router 是 React 应用程序的声明式路由。

// React Router 配置
import React from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { useSelector } from 'react-redux';

// 组件导入
import Home from './pages/Home';
import Login from './pages/Login';
import Register from './pages/Register';
import Dashboard from './pages/Dashboard';
import Profile from './pages/Profile';
import Products from './pages/Products';
import ProductDetail from './pages/ProductDetail';
import NotFound from './pages/NotFound';

// 私有路由组件
const PrivateRoute = ({ children }) => {
  const { currentUser } = useSelector((state) => state.user);
  
  return currentUser ? children : <Navigate to="/login" />;
};

const AppRouter = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/login" element={<Login />} />
        <Route path="/register" element={<Register />} />
        
        {/* 受保护的路由 */}
        <Route path="/dashboard" element={
          <PrivateRoute>
            <Dashboard />
          </PrivateRoute>
        } />
        
        <Route path="/profile" element={
          <PrivateRoute>
            <Profile />
          </PrivateRoute>
        } />
        
        <Route path="/products" element={<Products />} />
        <Route path="/products/:id" element={<ProductDetail />} />
        
        {/* 404 页面 */}
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
};

export default AppRouter;

4.5 前端架构

React 应用
组件层
状态管理层
服务层
路由层
工具层
页面组件
UI组件
布局组件
表单组件
Redux Store
Actions
Reducers
Middleware
API 服务
认证服务
存储服务
公共路由
私有路由
路由守卫
工具函数
自定义钩子
常量

5. 全栈集成

5.1 前后端通信

浏览器客户端 React 前端 Express API 数据库 用户操作 HTTP请求 发送JWT令牌进行身份验证 查询/操作数据 返回数据 JSON响应 包含状态码和数据 更新UI 浏览器客户端 React 前端 Express API 数据库

5.2 身份验证流程

用户 前端 (React) 后端 (Express) 数据库 输入登录凭据 POST /api/auth/login 验证用户凭据 返回用户数据 生成JWT令牌 返回令牌和用户信息 存储令牌(localStorage) 后续授权请求 发送请求(带Authorization头) 验证JWT令牌 返回受保护的资源 令牌过期 发送请求(带过期令牌) 返回401未授权 清除令牌并重定向到登录页 用户 前端 (React) 后端 (Express) 数据库

5.3 完整的全栈应用架构

基础设施
持久化层
数据层
API层
前端层
服务器 - AWS/Azure
CI/CD - Jenkins/GitHub Actions
监控 - Prometheus
日志 - ELK Stack
MongoDB/MySQL
文件存储
数据模型
数据访问对象
ORM - Mongoose/Sequelize
缓存 - Redis
Express 服务器
路由控制器
中间件
认证服务
业务逻辑
React 应用
状态管理 - Redux
路由 - React Router
UI库 - Material UI
API 客户端 - Axios

6. 数据建模与持久化

6.1 MongoDB 数据模型

// 用户模型
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');

const userSchema = new mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true,
    trim: true,
    minlength: 3,
    maxlength: 30,
  },
  email: {
    type: String,
    required: true,
    unique: true,
    trim: true,
    lowercase: true,
    match: [/^\S+@\S+\.\S+$/, '请提供有效的电子邮件地址'],
  },
  password: {
    type: String,
    required: true,
    minlength: 6,
  },
  role: {
    type: String,
    enum: ['user', 'admin'],
    default: 'user',
  },
  profilePicture: String,
  bio: {
    type: String,
    maxlength: 500,
  },
  isActive: {
    type: Boolean,
    default: true,
  },
  lastLogin: Date,
}, {
  timestamps: true,
});

// 密码哈希中间件
userSchema.pre('save', async function(next) {
  if (!this.isModified('password')) return next();
  
  try {
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
    next();
  } catch (error) {
    next(error);
  }
});

// 验证密码方法
userSchema.methods.comparePassword = async function(candidatePassword) {
  return bcrypt.compare(candidatePassword, this.password);
};

const User = mongoose.model('User', userSchema);

module.exports = User;

6.2 MySQL 数据建模

-- 用户表
CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(30) NOT NULL UNIQUE,
  email VARCHAR(100) NOT NULL UNIQUE,
  password VARCHAR(255) NOT NULL,
  role ENUM('user', 'admin') DEFAULT 'user',
  profile_picture VARCHAR(255),
  bio TEXT,
  is_active BOOLEAN DEFAULT TRUE,
  last_login DATETIME,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 产品表
CREATE TABLE products (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  description TEXT,
  price DECIMAL(10, 2) NOT NULL,
  stock INT NOT NULL DEFAULT 0,
  category_id INT,
  image_url VARCHAR(255),
  is_featured BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL
);

-- 类别表
CREATE TABLE categories (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50) NOT NULL UNIQUE,
  description TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 订单表
CREATE TABLE orders (
  id INT AUTO_INCREMENT PRIMARY KEY,
  user_id INT NOT NULL,
  status ENUM('pending', 'processing', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',
  total_amount DECIMAL(10, 2) NOT NULL,
  shipping_address TEXT NOT NULL,
  payment_method VARCHAR(50) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- 订单项表
CREATE TABLE order_items (
  id INT AUTO_INCREMENT PRIMARY KEY,
  order_id INT NOT NULL,
  product_id INT NOT NULL,
  quantity INT NOT NULL,
  price DECIMAL(10, 2) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
  FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT
);

-- 用户地址表
CREATE TABLE user_addresses (
  id INT AUTO_INCREMENT PRIMARY KEY,
  user_id INT NOT NULL,
  address_line1 VARCHAR(100) NOT NULL,
  address_line2 VARCHAR(100),
  city VARCHAR(50) NOT NULL,
  state VARCHAR(50) NOT NULL,
  postal_code VARCHAR(20) NOT NULL,
  country VARCHAR(50) NOT NULL,
  is_default BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- 产品评论表
CREATE TABLE product_reviews (
  id INT AUTO_INCREMENT PRIMARY KEY,
  product_id INT NOT NULL,
  user_id INT NOT NULL,
  rating INT NOT NULL CHECK (rating BETWEEN 1 AND 5),
  comment TEXT,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  UNIQUE (product_id, user_id)
);

6.3 数据关系建模

USERS int id PK string username string email string password enum role string profile_picture text bio boolean is_active datetime last_login timestamp created_at timestamp updated_at ORDERS int id PK int user_id FK enum status decimal total_amount text shipping_address string payment_method timestamp created_at timestamp updated_at USER_ADDRESSES int id PK int user_id FK string address_line1 string address_line2 string city string state string postal_code string country boolean is_default timestamp created_at timestamp updated_at PRODUCT_REVIEWS int id PK int product_id FK int user_id FK int rating text comment timestamp created_at timestamp updated_at CATEGORIES int id PK string name text description timestamp created_at timestamp updated_at PRODUCTS int id PK string name text description decimal price int stock int category_id FK string image_url boolean is_featured timestamp created_at timestamp updated_at ORDER_ITEMS int id PK int order_id FK int product_id FK int quantity decimal price timestamp created_at timestamp updated_at places has writes contains receives includes contains

7. API 开发与设计模式

7.1 模块化路由

// /routes/index.js - 路由主入口
const express = require('express');
const userRoutes = require('./userRoutes');
const productRoutes = require('./productRoutes');
const orderRoutes = require('./orderRoutes');
const authRoutes = require('./authRoutes');

const router = express.Router();

// API 版本控制
router.use('/v1/users', userRoutes);
router.use('/v1/products', productRoutes);
router.use('/v1/orders', orderRoutes);
router.use('/v1/auth', authRoutes);

module.exports = router;

// /routes/userRoutes.js - 用户相关路由
const express = require('express');
const userController = require('../controllers/userController');
const { authMiddleware, adminMiddleware } = require('../middleware/authMiddleware');

const router = express.Router();

// 公共路由
router.get('/:id/profile', userController.getUserProfile);

// 需要认证的路由
router.get('/me', authMiddleware, userController.getCurrentUser);
router.put('/me', authMiddleware, userController.updateProfile);
router.get('/me/orders', authMiddleware, userController.getUserOrders);

// 管理员路由
router.get('/', authMiddleware, adminMiddleware, userController.getAllUsers);
router.delete('/:id', authMiddleware, adminMiddleware, userController.deleteUser);

module.exports = router;

7.2 控制器模式

// /controllers/productController.js
const Product = require('../models/Product');
const { createError } = require('../utils/errorHandler');

// 控制器对象
const productController = {
  // 获取所有产品
  async getAllProducts(req, res, next) {
    try {
      const { category, search, minPrice, maxPrice, sort, limit = 10, page = 1 } = req.query;
      
      // 构建查询条件
      const query = {};
      
      if (category) {
        query.category_id = category;
      }
      
      if (search) {
        query.name = { $regex: search, $options: 'i' };
      }
      
      if (minPrice || maxPrice) {
        query.price = {};
        if (minPrice) query.price.$gte = parseFloat(minPrice);
        if (maxPrice) query.price.$lte = parseFloat(maxPrice);
      }
      
      // 构建排序条件
      let sortOptions = { createdAt: -1 }; // 默认按创建时间降序
      
      if (sort) {
        const [field, order] = sort.split(':');
        sortOptions = { [field]: order === 'desc' ? -1 : 1 };
      }
      
      // 计算分页
      const skip = (parseInt(page) - 1) * parseInt(limit);
      
      // 执行查询
      const products = await Product.find(query)
        .sort(sortOptions)
        .limit(parseInt(limit))
        .skip(skip);
      
      // 获取总数
      const total = await Product.countDocuments(query);
      
      res.json({
        products,
        pagination: {
          total,
          page: parseInt(page),
          limit: parseInt(limit),
          pages: Math.ceil(total / parseInt(limit)),
        },
      });
    } catch (error) {
      next(error);
    }
  },
  
  // 获取单个产品
  async getProductById(req, res, next) {
    try {
      const { id } = req.params;
      
      const product = await Product.findById(id);
      
      if (!product) {
        return next(createError(404, '找不到该产品'));
      }
      
      res.json(product);
    } catch (error) {
      next(error);
    }
  },
  
  // 创建产品
  async createProduct(req, res, next) {
    try {
      const productData = req.body;
      
      const newProduct = new Product(productData);
      await newProduct.save();
      
      res.status(201).json(newProduct);
    } catch (error) {
      next(error);
    }
  },
  
  // 更新产品
  async updateProduct(req, res, next) {
    try {
      const { id } = req.params;
      const updateData = req.body;
      
      const product = await Product.findByIdAndUpdate(
        id,
        updateData,
        { new: true, runValidators: true }
      );
      
      if (!product) {
        return next(createError(404, '找不到该产品'));
      }
      
      res.json(product);
    } catch (error) {
      next(error);
    }
  },
  
  // 删除产品
  async deleteProduct(req, res, next) {
    try {
      const { id } = req.params;
      
      const product = await Product.findByIdAndDelete(id);
      
      if (!product) {
        return next(createError(404, '找不到该产品'));
      }
      
      res.status(204).end();
    } catch (error) {
      next(error);
    }
  },
};

module.exports = productController;

7.3 服务层模式

// /services/orderService.js
const Order = require('../models/Order');
const Product = require('../models/Product');
const { createError } = require('../utils/errorHandler');

// 订单服务
const orderService = {
  // 创建订单
  async createOrder(orderData, userId) {
    // 验证产品库存
    const orderItems = orderData.items;
    let totalAmount = 0;
    
    // 验证所有产品是否有足够库存
    for (const item of orderItems) {
      const product = await Product.findById(item.productId);
      
      if (!product) {
        throw createError(404, `商品ID ${item.productId} 不存在`);
      }
      
      if (product.stock < item.quantity) {
        throw createError(400, `商品 ${product.name} 库存不足`);
      }
      
      // 计算项目价格
      item.price = product.price;
      totalAmount += product.price * item.quantity;
    }
    
    // 创建订单事务
    const session = await Order.startSession();
    session.startTransaction();
    
    try {
      // 创建订单
      const newOrder = new Order({
        user: userId,
        items: orderItems.map(item => ({
          product: item.productId,
          quantity: item.quantity,
          price: item.price
        })),
        totalAmount,
        shippingAddress: orderData.shippingAddress,
        paymentMethod: orderData.paymentMethod,
        status: 'pending'
      });
      
      await newOrder.save({ session });
      
      // 更新产品库存
      for (const item of orderItems) {
        await Product.findByIdAndUpdate(
          item.productId,
          { $inc: { stock: -item.quantity } },
          { session }
        );
      }
      
      // 提交事务
      await session.commitTransaction();
      session.endSession();
      
      return newOrder;
    } catch (error) {
      // 回滚事务
      await session.abortTransaction();
      session.endSession();
      throw error;
    }
  },
  
  // 获取用户订单
  async getUserOrders(userId) {
    return Order.find({ user: userId })
      .sort({ createdAt: -1 })
      .populate('items.product', 'name image_url');
  },
  
  // 获取订单详情
  async getOrderById(orderId, userId, isAdmin = false) {
    const query = { _id: orderId };
    
    // 如果不是管理员,只能查看自己的订单
    if (!isAdmin) {
      query.user = userId;
    }
    
    const order = await Order.findOne(query)
      .populate('user', 'username email')
      .populate('items.product');
      
    if (!order) {
      throw createError(404, '订单不存在');
    }
    
    return order;
  },
  
  // 更新订单状态
  async updateOrderStatus(orderId, status, userId, isAdmin = false) {
    const query = { _id: orderId };
    
    // 如果不是管理员,只能更新自己的订单
    if (!isAdmin) {
      query.user = userId;
      
      // 非管理员只能取消订单
      if (status !== 'cancelled') {
        throw createError(403, '没有权限执行此操作');
      }
      
      // 只能取消待处理或处理中的订单
      query.status = { $in: ['pending', 'processing'] };
    }
    
    const order = await Order.findOneAndUpdate(
      query,
      { status },
      { new: true, runValidators: true }
    );
    
    if (!order) {
      throw createError(404, '订单不存在或无法更新状态');
    }
    
    return order;
  },
};

module.exports = orderService;

7.4 错误处理模式

// /utils/errorHandler.js
// 创建自定义错误
const createError = (statusCode, message, details = null) => {
  const error = new Error(message);
  error.statusCode = statusCode;
  error.details = details;
  return error;
};

// 全局错误处理中间件
const errorHandler = (err, req, res, next) => {
  console.error('Error:', err);
  
  // 获取错误状态码和消息
  const statusCode = err.statusCode || 500;
  const message = err.message || '服务器内部错误';
  
  // 区分不同环境下的错误响应
  const response = {
    error: {
      message,
      status: statusCode,
    },
  };
  
  // 在开发环境中提供更详细的错误信息
  if (process.env.NODE_ENV === 'development') {
    response.error.stack = err.stack;
    if (err.details) {
      response.error.details = err.details;
    }
  }
  
  // MongoDB 验证错误处理
  if (err.name === 'ValidationError') {
    response.error.status = 400;
    response.error.message = '数据验证失败';
    response.error.details = Object.values(err.errors).map(e => e.message);
  }
  
  // MongoDB 重复键错误处理
  if (err.code === 11000) {
    response.error.status = 409;
    response.error.message = '数据已存在';
    const field = Object.keys(err.keyValue)[0];
    response.error.details = `${field} 已被使用`;
  }
  
  // JWT 错误处理
  if (err.name === 'JsonWebTokenError') {
    response.error.status = 401;
    response.error.message = '无效的认证令牌';
  }
  
  if (err.name === 'TokenExpiredError') {
    response.error.status = 401;
    response.error.message = '认证令牌已过期';
  }
  
  res.status(response.error.status).json(response);
};

module.exports = { createError, errorHandler };

8. 安全性与性能优化

8.1 安全最佳实践

// /config/security.js
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const mongoSanitize = require('express-mongo-sanitize');
const xss = require('xss-clean');
const hpp = require('hpp');
const cors = require('cors');

// 配置安全中间件
const configSecurity = (app) => {
  // 设置安全 HTTP 头
  app.use(helmet());
  
  // 防止 XSS 攻击
  app.use(xss());
  
  // 防止 NoSQL 注入
  app.use(mongoSanitize());
  
  // 防止参数污染
  app.use(hpp());
  
  // 配置 CORS
  app.use(cors({
    origin: process.env.CORS_ORIGIN || '*',
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: true,
  }));
  
  // 配置速率限制
  const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15分钟
    max: 100, // 每个IP在windowMs内最多100个请求
    message: {
      error: {
        message: '请求过多,请稍后再试',
        status: 429,
      },
    },
  });
  
  // 应用速率限制到所有请求
  app.use('/api', limiter);
  
  // 严格的认证路由限制
  const authLimiter = rateLimit({
    windowMs: 60 * 60 * 1000, // 1小时
    max: 10, // 每个IP每小时最多10次尝试
    message: {
      error: {
        message: '尝试次数过多,请稍后再试',
        status: 429,
      },
    },
  });
  
  // 应用认证限制到登录和注册路由
  app.use('/api/v1/auth/login', authLimiter);
  app.use('/api/v1/auth/register', authLimiter);
};

module.exports = configSecurity;

8.2 性能优化技术

// /config/performance.js
const compression = require('compression');
const { createClient } = require('redis');

// Redis 客户端
let redisClient;

// 配置性能优化
const configPerformance = async (app) => {
  // 启用 gzip 压缩
  app.use(compression());
  
  // 设置 Redis 缓存(如果配置了)
  if (process.env.REDIS_URL) {
    redisClient = createClient({
      url: process.env.REDIS_URL,
    });
    
    await redisClient.connect().catch(err => {
      console.error('Redis 连接失败:', err);
    });
    
    redisClient.on('error', (err) => {
      console.error('Redis 错误:', err);
    });
    
    console.log('Redis 缓存已启用');
  }
};

// 缓存中间件
const cacheMiddleware = (duration) => {
  return async (req, res, next) => {
    // 如果 Redis 未连接,跳过缓存
    if (!redisClient || !redisClient.isReady) {
      return next();
    }
    
    // 跳过非 GET 请求的缓存
    if (req.method !== 'GET') {
      return next();
    }
    
    // 创建缓存键
    const cacheKey = `api:${req.originalUrl}`;
    
    try {
      // 尝试从缓存获取数据
      const cachedData = await redisClient.get(cacheKey);
      
      if (cachedData) {
        // 返回缓存数据
        const data = JSON.parse(cachedData);
        return res.json(data);
      }
      
      // 修改 res.json 方法以缓存响应
      const originalJson = res.json;
      res.json = function(data) {
        // 将数据保存到缓存
        redisClient.setEx(cacheKey, duration, JSON.stringify(data))
          .catch(err => console.error('Redis 缓存错误:', err));
          
        // 调用原始 json 方法
        return originalJson.call(this, data);
      };
      
      next();
    } catch (error) {
      console.error('缓存错误:', error);
      next();
    }
  };
};

// 清除缓存模式
const clearCache = async (pattern) => {
  if (!redisClient || !redisClient.isReady) {
    return;
  }
  
  try {
    // 查找匹配的键
    const keys = await redisClient.keys(pattern);
    
    // 如果有匹配的键,删除它们
    if (keys.length > 0) {
      await redisClient.del(keys);
      console.log(`已清除 ${keys.length} 个缓存键`);
    }
  } catch (error) {
    console.error('清除缓存错误:', error);
  }
};

module.exports = {
  configPerformance,
  cacheMiddleware,
  clearCache,
};

8.3 日志系统

// /utils/logger.js
const winston = require('winston');
const { format, transports, createLogger } = winston;
const path = require('path');

// 定义日志格式
const logFormat = format.combine(
  format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
  format.errors({ stack: true }),
  format.splat(),
  format.json()
);

// 创建 logger 实例
const logger = createLogger({
  level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
  format: logFormat,
  defaultMeta: { service: 'api-service' },
  transports: [
    // 控制台输出
    new transports.Console({
      format: format.combine(
        format.colorize(),
        format.printf(
          info => `${info.timestamp} ${info.level}: ${info.message}${info.stack ? '\n' + info.stack : ''}`
        )
      ),
    }),
  ],
});

// 在生产环境中添加文件传输
if (process.env.NODE_ENV === 'production') {
  logger.add(
    new transports.File({
      filename: path.join(__dirname, '../logs/error.log'),
      level: 'error',
      maxsize: 10485760, // 10MB
      maxFiles: 5,
    })
  );
  
  logger.add(
    new transports.File({
      filename: path.join(__dirname, '../logs/combined.log'),
      maxsize: 10485760, // 10MB
      maxFiles: 5,
    })
  );
}

// 捕获未处理的异常和拒绝
logger.exceptions.handle(
  new transports.File({ filename: path.join(__dirname, '../logs/exceptions.log') })
);

// 中间件:请求日志
const requestLogger = (req, res, next) => {
  const startTime = new Date();
  
  // 请求完成时的回调
  res.on('finish', () => {
    const duration = new Date() - startTime;
    
    logger.info({
      type: 'request',
      method: req.method,
      path: req.path,
      query: req.query,
      statusCode: res.statusCode,
      duration: `${duration}ms`,
      userAgent: req.get('User-Agent'),
      ip: req.ip,
    });
  });
  
  next();
};

module.exports = { logger, requestLogger };

9. 部署与 DevOps

9.1 Docker 容器化

# Dockerfile
FROM node:18-alpine

# 创建应用目录
WORKDIR /usr/src/app

# 安装应用依赖
COPY package*.json ./
RUN npm ci --only=production

# 复制应用代码
COPY . .

# 设置环境变量
ENV NODE_ENV=production
ENV PORT=3000

# 暴露端口
EXPOSE 3000

# 启动应用
CMD ["node", "server.js"]
# docker-compose.yml
version: '3'

services:
  app:
    build: .
    restart: always
    ports:
      - "3000:3000"
    depends_on:
      - mongodb
      - redis
    environment:
      - NODE_ENV=production
      - PORT=3000
      - MONGODB_URI=mongodb://mongodb:27017/myapp
      - REDIS_URL=redis://redis:6379
      - JWT_SECRET=your_jwt_secret
      - CORS_ORIGIN=https://yourdomain.com
    volumes:
      - ./logs:/usr/src/app/logs
    networks:
      - app-network

  mongodb:
    image: mongo:6
    restart: always
    ports:
      - "27017:27017"
    volumes:
      - mongodb-data:/data/db
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  mongodb-data:
  redis-data:

9.2 CI/CD 流水线

# .github/workflows/main.yml
name: Node.js CI/CD

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x, 18.x]

    steps:
    - uses: actions/checkout@v3
    
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run linting
      run: npm run lint
    
    - name: Run tests
      run: npm test
      
  build-and-deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Use Node.js 18.x
      uses: actions/setup-node@v3
      with:
        node-version: 18.x
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Build
      run: npm run build
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v2
    
    - name: Login to DockerHub
      uses: docker/login-action@v2
      with:
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_TOKEN }}
    
    - name: Build and push Docker image
      uses: docker/build-push-action@v4
      with:
        context: .
        push: true
        tags: yourusername/yourapp:latest
    
    - name: Deploy to server
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.SSH_HOST }}
        username: ${{ secrets.SSH_USERNAME }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        script: |
          cd /path/to/your/app
          docker-compose pull
          docker-compose up -d

9.3 部署流程

代码提交
自动化测试
失败
成功
失败
成功
开发阶段
CI/CD 流水线
测试通过?
通知开发者
构建 Docker 镜像
推送到容器仓库
部署到测试环境
性能和验收测试
部署到生产环境
监控系统性能
发现问题?
回滚部署
完成部署

结语
感谢您的阅读!期待您的一键三连!欢迎指正!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2383651.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ubuntu sh安装包的安装方式

ubuntu sh安装包的安装方式以Miniconda2为例 https://repo.anaconda.com/miniconda/ 如果需要python2.7版本可下载以下版本 Miniconda2-latest-Linux-x86_64.sh 打开终端输入安装命令 sudo sh Miniconda2-latest-Linux-x86_64.sh 然后按提示安装&#xff0c;注意安装位置 …

OpenAI宣布:核心API支持MCP,助力智能体开发

今天凌晨&#xff0c;OpenAI全资收购io的消息成为头条。同时&#xff0c;OpenAI还宣布其核心API——Responses API支持MCP服务。过去&#xff0c;开发智能体需通过函数调用与外部服务交互&#xff0c;过程复杂且延迟高。而今&#xff0c;Responses API支持MCP后&#xff0c;开发…

微服务中的 AKF 拆分原则:构建可扩展系统的核心方法论

在数字化浪潮的推动下&#xff0c;互联网应用规模呈指数级增长&#xff0c;传统单体架构逐渐暴露出难以扩展、维护成本高等问题&#xff0c;微服务架构应运而生并成为企业应对复杂业务场景的主流选择。然而&#xff0c;随着业务的不断扩张和用户量的持续增加&#xff0c;如何确…

vue element-plus 集成多语言

main.js中 // 引入i18n import i18n from /i18n/index 使用i18 app.use(i18n) 在App.vue中 <template><el-config-provider :locale"locale" namespace"el" size"small"><router-view /></el-config-provider> </tem…

如何测试JWT的安全性:全面防御JSON Web Token的安全漏洞

在当今的Web应用安全领域&#xff0c;JSON Web Token(JWT)已成为身份认证的主流方案&#xff0c;但OWASP统计显示&#xff0c;错误配置的JWT导致的安全事件占比高达42%。本文将系统性地介绍JWT安全测试的方法论&#xff0c;通过真实案例剖析典型漏洞&#xff0c;帮助我们构建全…

车载网关策略 --- 车载网关重置前的请求转发机制

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…

EtpBot:安卓自动化脚本开发神器

EtpBot 是什么&#xff1f; EtpBot是一款专为安卓设备设计的自动化脚本开发工具&#xff0c;支持用户通过编写脚本实现自动化操作。该模块提供了丰富的API接口&#xff0c;涵盖点击、滑动、输入、截图等常见操作&#xff0c;帮助开发者快速构建自动化任务。ETPBot支持多设备并行…

连锁企业管理系统对门店运营的促进作用

连锁企业管理系统通过整合数字化工具与流程优化&#xff0c;能从多维度提升门店运营效率与竞争力&#xff0c;以下是其对门店运营的具体促进作用&#xff1a; 一、数据化管理&#xff1a;精准决策与运营监控 实时数据同步与分析 系统可整合各门店销售数据、库存信息、客流统计…

现代生活健康养生新策略

在充满挑战的现代生活中&#xff0c;各种健康问题悄然来袭&#xff0c;亚健康状态困扰着不少人。摒弃中医概念&#xff0c;运用现代科学理念&#xff0c;也能找到行之有效的养生之道。​ 饮食上&#xff0c;遵循 “彩虹饮食法” 能让营养摄入更全面。不同颜色的蔬果富含不同的…

车载以太网网络测试-27【SOME/IP-SD简述】

文章目录 1 摘要2 SOME/IP-SD协议介绍2.1 定义与作用2.2 SOMEIP/SD协议通俗易懂的理解2.2.1 SOMEIP/SD协议是什么&#xff1f;2.2.2 通信流程&#xff08;简化&#xff09;2.2.3 车载功能示例2.2.4 类比理解 2.3 SOME/IP-SD报文结构2.3.1 Flags2.3.1.1 REBOOT (Bit 7)2.3.1.2 U…

【Redis8】最新安装版与手动运行版

1. 下载 Redis 百度网盘 2. 解压后直接运行 redis-server.exe 3. 使用安装版 双击 install_redis_service.bat 输入安装路径&#xff08;请提前创建好安装路径&#xff09;后直接回车下一步直接回车即可&#xff0c;因为是使用配置模板文件为默认解压出来的&#xff0c;然后…

Spring Boot 集成 Elasticsearch【实战】

前言&#xff1a; 上一篇我们简单分享了 Elasticsearch 的一些概念性的知识&#xff0c;本篇我们来分享 Elasticsearch 的实际运用&#xff0c;也就是在 Spring Booot 项目中使用 Elasticsearch。 Elasticsearch 系列文章传送门 Elasticsearch 基础篇【ES】 Elasticsearch …

06算法学习_58. 区间和

58. 区间和 06算法学习_58. 区间和题目描述&#xff1a;个人代码&#xff1a;学习思路&#xff1a;第一种写法&#xff1a;题解关键点&#xff1a; 个人学习时疑惑点解答&#xff1a; 06算法学习_58. 区间和 卡码网题目链接: 59. 螺旋矩阵 II 题目描述&#xff1a; 58. 区间…

Python爬虫之路(14)--playwright浏览器自动化

playwright 前言 ​ 你有没有在用 Selenium 抓网页的时候&#xff0c;体验过那种「明明点了按钮&#xff0c;它却装死不动」的痛苦&#xff1f;或者那种「刚加载完页面&#xff0c;它又刷新了」的抓狂&#xff1f;别担心&#xff0c;你不是一个人——那是 Selenium 在和现代前…

Python开启智能之眼:OpenCV+深度学习实战

开篇导言 场景痛点 "某汽车零部件厂每月因人工质检遗漏损失300万,直到部署了基于Python的视觉检测系统..." 传统质检效率低下、成本高昂 深度学习技术带来的产业变革 Python在视觉识别领域的独特优势 一、技术架构解析 1.1 系统组成模块 图表 代码 下载 检测结…

华为模拟器练习简单的拓扑图(3台路由器和2台pc)

1、题目要求 根据下图&#xff0c;pc1连通pc2&#xff0c;实现不同网段直接的互通 2、思路整理 2.1 根据图上的要求&#xff0c;为主机和路由器相连接的端口设置对应IP地址&#xff08;子网掩码都是24位&#xff09;,路由器连接pc的那个端口&#xff0c;是主机pc的网关 2.2 …

uniapp生成的app,关于跟其他设备通信的支持和限制

以下内容通过AI生成&#xff0c;这里做一下记录。 蓝牙 移动应用&#xff08;App&#xff09;通过蓝牙与其他设备通信&#xff0c;是通过分层协作实现的。 一、通信架构分层 应用层&#xff08;App&#xff09; 调用操作系统提供的蓝牙API&#xff08;如Android的BluetoothA…

Proxmox 主机与虚拟机全部断网问题排查与解决记录

Proxmox 主机与虚拟机全部断网问题排查与解决记录 关键词&#xff1a;Proxmox、e1000e、板载网卡、断网、网络桥接、Hardware Unit Hang、网卡挂死 背景 近期在使用 Proxmox VE 管理服务器时&#xff0c;遇到一个奇怪的问题&#xff1a;每当在某个虚拟机中执行某些操作&#x…

力扣560.和为K的子数组

文章目录 题目介绍题解 题目介绍 题解 前缀和哈希表&#xff08;两数之和&#xff09;&#xff1a; 代码如下&#xff1a; class Solution {public int subarraySum(int[] nums, int k) {int n nums.length;int[] s new int[n 1];for (int i 0; i < n; i) {s[i 1] …

MySQL——4、表的约束

表的约束 1、空属性2、默认值3、列描述4、zerofill5、主键6、自增长7、唯一键8、外键9、综合案例 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性…