
这篇主要是把一个简单后端的流程串起来:Node.js 接收请求,PostgreSQL 存数据,Redis 存缓存,最后把结果返回给前端。
//Web服务器框架 处理http请求,定义路由
const express = require('express')
//PostgreSQL驱动 连接数据库,执行SQL
const { Client } = require('pg')
//环境变量加载器 把.env文件里的密钥读进代码
const dotenv = require('dotenv')
//密码哈希工具 注册是加密密码 登录时比对密码
const bcrypt = require('bcrypt')
//Redis驱动 连接 Redis 缓存、读写缓存数据
const redis = require('redis')
关于 Client,这里用的是解构赋值,意思是只需要 pg 包中的 Client 这一个功能。
引入之后就是初始化配置。
dotenv.config()
它会读取项目根目录的 .env 文件,把里面的键值对放进 process.env 对象中。
.env文件
DATABASE_URL='xxxxxxxxxxxxxxxxxxxxxx'
REDIS_URL='xxxxxxxxxxxxxxxxxxxxxxxxx'
接着创建 PostgreSQL 和 Redis 客户端实例。这里只是创建,还没有真正连接。
const client = new Client(process.env.DATABASE_URL)
const redisClient = redis.createClient({
url:process.env.REDIS_URL
})
最后创建 Express 应用实例,后面的 app.get、app.post 等都会挂在它身上。
const app = express()
app.use(express.json())
这是注册一个中间件。如果前端发来的请求体是 JSON 格式,它会帮我们解析成 JS 对象,放进 req.body。
app.get('/',(req.res)=>{
res.send('hello world')
})
简单来说,有人用 GET 方法访问根路径时,就回复 hello world。
注册接口则是把用户信息写进数据库。
app.post('/register', async (req, res) => {
try {
await client.query(`insert into users (name,password,email) values ($1,$2,$3)`, [req.body.name, await bcrypt.hash(req.body.password, 10), req.body.email])
res.json({ message: '注册成功' })
} catch (err) {
console.log(err)
res.status(400).json({ message: '注册失败' })
}
})
登录时,不是把密码再 hash 一次后直接比较,而是用 bcrypt.compare 比对“用户输入的密码”和“数据库里存的哈希值”。
app.post('/login', async (req, res) => {
try {
const data = await client.query(`select * from users where email = $1`, [req.body.email])
if(data.rows.length === 0){
res.status(400).json({message:'用户不存在'})
return
}
if (await bcrypt.compare(req.body.password, data.rows[0].password)) {
res.json({ message: '登录成功',data:data.rows[0].id })
}else{
res.status(400).json({message:'密码错误'})
return
}
} catch (err) {
console.log(err)
res.status(400).json({ message: '登录失败' })
}
})
GET 请求和 POST 请求里,req 后面跟的内容通常不一样:
什么是 URL 参数?
https://xxx.com/details?teamid=0 ?后面的teamid=0 就是参数
下面这个接口是查用户资料。它会先查 Redis,有缓存就直接返回;没有缓存才去查 PostgreSQL,然后把结果写回 Redis。
app.get('/profile',async (req,res) =>{
const id = req.query.id
const cached = await redisClient.get(id)
try{
if(cached){
res.json({message:"用户信息已缓存",data:JSON.parse(cached)})
}else{
const userId = await client.query('select id,name,email,created_at from users where id = $1',[id])
await redisClient.set(id,JSON.stringify(userId.rows[0]))
res.json({message:"用户信息已缓存成功",data:userId.rows[0]})
}
}catch(error){
res.status(400).json({message:error.message})
}
})
Redis 只能存字符串,所以对象写进去之前,要先用 JSON.stringify 转成字符串。
这里用户的 id 写在 URL 里,别人修改 id 后就可能查看别人的账号。更关键的还是要判断:当前用户有没有权限查看这份资料。
app.listen(3000, async () => {
await client.connect()
await redisClient.connect()
})
把连接写在这里,想表达的就是:服务启动时,也把 PostgreSQL 和 Redis 连上。这样整个流程就串起来了。
如果只用一句话理解这段代码,那就是:Express 负责接请求,PostgreSQL 负责存用户数据,bcrypt 负责处理密码,Redis 负责缓存用户信息。
整个流程就是:先引入工具和配置,再定义路由,路由里查数据库或缓存,最后启动服务器。