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) {
// 失败逻辑
}
})