Node.js + 微信小程序

本文主要介绍如何使用 node(Express.js) 完成一些后端业务的开发,例如 数据库连接,发送邮件验证码。
使用 node 连接本地数据库
- 安装 node.js
前往官网下载 node.js。
安装成功后,使用命令查看 node 版本:
node -v出现版本号,说明 node 已经安装成功。同时,npm 也已经安装成功,可以输入 npm -v 查看版本号。
- 安装依赖
在你的计算机任何地方创建一个文件夹(可以在微信小程序根目录),进入文件夹 右键 在终端中打开,依次输入以下命令:
初始化项目,将会自动创建 package.json 配置文件:
npm init -y安装 Express 框架,用于快速创建HTTP服务器:
npm install express --save安装 mysql 的软件包:
npm install mysql --save安装 cors 跨域中间件:
npm install cors --save- 创建数据库连接文件
进行此步之前,请确保已经创建好数据库和表,并数据库连接正常。
在文件夹下创建 server.js ,输入以下代码:
const express = require("express");
const mysql = require("mysql");
const cors = require("cors");
const app = express();
app.use(cors());
// 数据库配置
const db = mysql.createConnection({
host: "localhost",
user: "root",
password: "password",
database: "database name",
});
// 连接数据库
db.connect((err) => {
if (err) throw err;
console.log("MySQL connected");
});
// 路由 获取全部用户
app.get("/allusers", (req, res) => {
const sql = "SELECT * FROM tb_user";
db.query(sql, (err, result) => {
if (err) throw err;
res.json({ code: 200, data: result });
});
});
// 路由 根据id获取用户
app.get("/user/:id", (req, res) => {
// 验证ID格式
const userId = parseInt(req.params.id);
if (isNaN(userId)) {
return res.status(400).json({
code: 400,
message: "Invalid book ID format",
});
}
// 使用参数化查询防止SQL注入
const sql = "SELECT * FROM tb_user WHERE id = ?";
db.query(sql, [userId], (err, result) => {
if (err) {
console.error("Database error:", err);
return res.status(500).json({
code: 500,
message: "Database query failed",
});
}
if (result.length === 0) {
return res.status(404).json({
code: 404,
message: "Book not found",
});
}
// 返回查询到的第一条记录
res.json({ code: 200, data: result[0] });
});
});
app.listen(3000, () => console.log("Server running on port 3000"));- 启动服务
在文件夹中 打开 终端,输入以下命令:
node server.js- 访问请求测试 可以在浏览器中访问
http://localhost:3000/allusers,如果看到返回的数据,说明连接成功。
或在小程序中进行请求:
// 所有用户
wx.request({
url: "http://localhost:3000/allusers",
methods: "GET",
success: (res) => {
console.log(res.data);
},
});
// 根据id获取用户
wx.request({
url: "http://localhost:3000/user/" + userid,
methods: "GET",
success: (res) => {
console.log(res.data);
},
});问题
Client does not support authentication protocol requested by server...
这是由于最新的 MySQL 模块并未完全支持 MySQL 8.0 的 caching_sha2_password 加密方式,而 MySQL 8.0 中默认仍然是 caching_sha2_password 加密方式,因此用户认证不通过。
可以通过指令方式修改:
mysql> alter user 'root'@'localhost' identified with mysql_native_password by '123456';
Query OK, 0 rows affected (0.01 sec)使用 node 发送邮箱验证码
- 获取授权码
- 首先使用个人账号登录网页版QQ邮箱
- 登录后找到设置,点击设置
- 进入设置,点击账号
- 找到并勾选SMTP发信后保存到服务器
- 找到管理服务并点击
- 进到账号与安全,往下拉,找到并点击生成授权码,然后进行短信验证
- 验证通过,生成授权码,复制授权码
- 安装依赖
先确保成功安装 node 后,安装 nodemailer 邮件发送软件包:
npm install nodemailer --save安装 Express 框架,用于快速创建HTTP服务器:
npm install express --save- 创建邮箱连接文件
const express = require("express");
const nodemailer = require("nodemailer"); // 邮件模块
const app = express();
app.use(express.json()); // JSON解析中间件
app.use(express.urlencoded({ extended: true })); // URL编码解析
// 邮件传输器配置
const transporter = nodemailer.createTransport({
host: "smtp.qq.com", // QQ邮箱SMTP服务器
port: 465, // SSL端口
secure: true, // 使用SSL
auth: {
user: "[email protected]", // 发送邮箱
pass: "XXXX", // 邮箱授权码
},
});
// 生成6位随机验证码
function generateVerificationCode() {
return Math.floor(100000 + Math.random() * 900000).toString();
}
// 发送验证码接口
app.post("/sendcode", (req, res) => {
const email = req.body.email; // 从前端获取邮箱地址
const verificationCode = generateVerificationCode();
// // 配置邮件内容
const mailOptions = {
from: '"XXXX" <[email protected]>', // 发件人信息
to: email, // 收件人邮箱
subject: "您的验证码", // 邮件主题
text: `您的验证码是:${verificationCode},3分钟内有效`, // 纯文本内容
html: `<b>${verificationCode}</b><p>该验证码3分钟内有效</p>`, // HTML内容
};
// 发送邮件
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.error("发送失败:", error);
return res.status(500).json({ code: 500, message: "验证码发送失败" });
}
console.log("验证码已发送:", info.messageId);
res.json({ code: 200, message: "验证码已发送至邮箱" });
});
});
app.listen(3000, () => console.log("Server running on port 3000"));在进行测试访问之前,同样需要先启动服务:
node server.js由于 /sendcode 验证码接口是 POST 请求,不能直接通过浏览器测试,可以使用 postman 进行测试,或通过小程序 wx.request 完成请求:
wx.request({
url: "http://localhost:3000/sendcode",
methods: "POST",
data: {
email: this.data.email,
},
success: (res) => {
console.log(res.data);
},
});最佳方案
当后端体量大起来后,显然将业务逻辑、数据库配置、路由都放在一起是不合适的,不利于维护与阅读。以下是按照 Express 标准文件结构重构后的项目结构方案:
src
app.js
package.json
config
db.js
middleware.js
services
userService.js
routes
userRoutes.js
/**
* 入口文件
*/
const express = require("express");
const applyMiddleware = require("./config/middleware");
// 初始化应用
const app = express();
// 应用中间件
applyMiddleware(app);
// 路由导入
const userRoutes = require("./routes/userRoutes");
// 挂载路由
app.use("/api/user", userRoutes);
// 启动服务器
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});{
"name": "XXX",
"description": "XXX",
"author": "XXX",
"version": "1.0.0",
"engines": {
"node": "^18.20.0 || >=20.0.0"
},
"dependencies": {
"cors": "^2.8.5",
"express": "^5.1.0",
"mysql": "^2.18.1",
"nodemailer": "^6.10.1"
}
}/**
* 数据库配置
*/
const mysql = require("mysql");
const dbConfig = {
host: "localhost",
user: "username", // 用户
password: "password", // 密码
database: "database_name", // 数据库名
};
const db = mysql.createConnection(dbConfig);
// 连接数据库
db.connect((err) => {
if (err) throw err;
console.log("MySQL connected");
});
module.exports = db;/**
* 中间件配置
*/
const express = require("express");
const cors = require("cors");
const applyMiddleware = (app) => {
app.use(cors()); // 跨域
app.use(express.json()); // JSON解析中间件
app.use(express.urlencoded({ extended: true }));
};
module.exports = applyMiddleware;/**
* 用户业务逻辑
*/
const createUserService = (db) => {
// 通用查询方法
const query = (sql, params) => {
return new Promise((resolve, reject) => {
db.query(sql, params, (err, results) => {
err ? reject(err) : resolve(results);
});
});
};
// 登录
const userLogin = async (email, password) => {
const [user] = await query("SELECT * FROM tb_user WHERE email = ? AND password = ?", [
email,
password,
]);
return user;
};
return {
// 登录
userLoginHandler: async (req, res) => {
try {
const email = req.params.email;
const password = req.params.password;
const user = await userLogin(email, password);
if (user) {
res.json({
code: 200,
data: user,
});
} else {
res.status(401).json({
code: 401,
message: "密码错误",
});
}
} catch (err) {
console.error(err);
res.status(500).json({
code: 500,
message: "登录失败",
});
}
},
};
};
module.exports = createUserService;/**
* 用户路由配置
*/
const express = require("express");
const router = express.Router();
const db = require("../config/db");
const userService = createUserService(db);
const createUserService = require("../services/userService");
router.get("/login/:email/:password", userService.userLoginHandler); // 登录
module.exports = router;使用以上的项目结构,可以将后端逻辑清晰的分开,便于维护和扩展。
访问示例当中的登录请求则是:
wx.request({
url: "http://localhost:3000/api/user/login/" + email + "/" + password,
method: "GET",
success(res) {
// 成功逻辑
},
fail(err) {
// 失败逻辑
},
});