为什么 Redis 存储验证码更合适?

  • Redis 是一个内存数据库,非常适合用于存储短期有效的数据,例如验证码,因为它非常快速,并且可以设置过期时间(TTL,Time to Live)。当验证码过期时,它会自动删除,不需要手动清理。
  • 将验证码存储在 Redis 中可以减轻数据库负担,避免冗余的数据存储。

npm install redis

基本的 Redis 使用示例

示例:连接 Redis 并使用基本的 setget 操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

const redis = require('redis');

// 创建客户端并连接到 Redis 服务器
const client = redis.createClient({
host: 'localhost', // Redis 服务器地址,默认为 localhost
port: 6379, // Redis 端口,默认为 6379
// 如果需要身份验证,使用密码
// password: 'your-redis-password'
});

// 连接事件
client.on('connect', () => {
console.log('Connected to Redis');
});

client.on('error', (err) => {
console.log('Redis error: ' + err);
});

// 设置值到 Redis
client.set('myKey', 'Hello, Redis!', redis.print);

// 获取 Redis 中的值
client.get('myKey', (err, reply) => {
if (err) {
console.error('Error getting value from Redis:', err);
} else {
console.log('Stored value:', reply); // 输出:Hello, Redis!
}
});

// 关闭 Redis 客户端
client.quit();

4. 使用 Redis 存储验证码

根据之前的注册逻辑,你可以使用 Redis 来存储验证码并设置过期时间。这里是一个使用 Redis 来存储验证码的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

const redis = require('redis');
const client = redis.createClient({
host: 'localhost',
port: 6379,
});

// 存储验证码到 Redis 并设置过期时间(例如 5 分钟)
function storeVerificationCode(email, code) {
client.setex(email, 300, code); // 设置过期时间为 300 秒(5分钟)
}

// 检查验证码是否匹配
function checkVerificationCode(email, code, callback) {
client.get(email, (err, storedCode) => {
if (err) {
return callback(err);
}
if (storedCode === code) {
callback(null, true);
} else {
callback(null, false);
}
});
}

5. 完整的注册流程(存储验证码到 Redis)

你可以将 Redis 集成到之前的用户注册逻辑中,使用 Redis 存储和验证验证码。以下是修改后的代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

const express = require('express');
const nodemailer = require('nodemailer');
const bodyParser = require('body-parser');
const redis = require('redis');
const dotenv = require('dotenv');
dotenv.config();

const app = express();
const port = 3000;

// Redis 客户端连接
const client = redis.createClient({
host: 'localhost',
port: 6379,
});

app.use(bodyParser.json());

// 邮箱验证码发送路由
app.post('/send-verification-code', (req, res) => {
const { email, nickname, password, confirmPassword } = req.body;

if (!email || !nickname || !password || !confirmPassword) {
return res.status(400).send('Please fill all required fields.');
}

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return res.status(400).send('Invalid email format.');
}

if (password !== confirmPassword) {
return res.status(400).send('Passwords do not match.');
}

const code = Math.floor(1000 + Math.random() * 9000).toString();

// 使用 Nodemailer 发送验证码
const transporter = nodemailer.createTransport({
service: 'SendGrid',
auth: {
user: process.env.SENDGRID_USERNAME,
pass: process.env.SENDGRID_PASSWORD,
},
});

const mailOptions = {
from: process.env.SENDGRID_FROM_EMAIL,
to: email,
subject: 'Email Verification Code',
text: `Your verification code is: ${code}`,
};

transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return res.status(500).send('Failed to send verification code.');
}

// 将验证码存储到 Redis 中,设置 5 分钟过期
client.setex(email, 300, code);

res.send('Verification code sent.');
});
});

// 用户注册路由
app.post('/register', (req, res) => {
const { email, verificationCode, nickname, password } = req.body;

// 从 Redis 获取验证码并进行验证
client.get(email, (err, storedCode) => {
if (err) {
return res.status(500).send('Redis error.');
}
if (!storedCode || storedCode !== verificationCode) {
return res.status(400).send('Invalid or expired verification code.');
}

// 用户注册成功(这里通常会保存到数据库)
res.send('User registered successfully.');
});
});

app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});

6. Redis 高级用法

  • 设置过期时间:使用 client.setex 可以直接设置键值对的过期时间。
  • 删除数据:使用 client.del(key) 来删除某个键。
  • 查看剩余过期时间:使用 client.ttl(key) 来查看某个键的剩余过期时间。

Redis 是一个非常快速的内存存储系统,广泛用于缓存、会话管理、消息队列等场景。如果在生产环境中使用 Redis,记得将其配置好并处理好错误和重试机制。

我使用的redis 客户端 mac 我该如何查看我的密码

这个错误 ReplyError: NOAUTH Authentication required 表示你连接的 Redis 服务器启用了 密码验证,而你的应用程序没有提供正确的密码。

步骤 1: 找到 redis.conf 配置文件的位置

在默认情况下,Redis 的配置文件通常位于 /usr/local/etc/redis//etc/redis/ 目录下。你可以通过以下命令来查找它:

1
find / -name redis.conf

如果你使用 Homebrew 安装了 Redis,默认的配置文件路径通常是:

1
/usr/local/etc/redis.conf

步骤 2: 查找 requirepass 配置项

打开 redis.conf 配置文件,并查找 requirepass 这一行,它是用来设置 Redis 密码的。

1
cat /usr/local/etc/redis.conf | grep requirepass

你会看到类似下面的内容:

1
# requirepass foobared
  • 如果这行前有 #,表示密码功能没有启用。
  • 如果没有 #,则会看到类似 requirepass your-redis-password 的内容,表示 Redis 密码已启用,your-redis-password 就是你的密码。

真实使用

redis.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const redis = require('redis');

// 创建 Redis 客户端并配置
const client = redis.createClient({
host: 'localhost', // 或者使用环境变量配置
port: 6379, // Redis 端口,默认为 6379
});

// 连接成功后输出
client.on('connect', () => {
console.log('Connected to Redis server');
});

// 错误处理
client.on('error', (err) => {
console.error('Error connecting to Redis:', err);
});

// 导出 Redis 客户端
module.exports = client;

app.js 中使用 Redis

app.js 中,你只需要导入 redis.js 文件并确保连接已经建立。这样,所有后续需要使用 Redis 的地方都会通过这个配置。

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

const express = require('express');
const redisClient = require('./redis'); // 引入 Redis 配置文件
const app = express();

// 你可以在这里使用 redisClient 进行 Redis 操作,例如
redisClient.set('test', 'Hello Redis', (err, reply) => {
if (err) {
console.error('Error setting Redis value:', err);
} else {
console.log('Redis test set reply:', reply);
}
});

// 路由等其他操作
app.get('/', (req, res) => {
res.send('Hello, Redis connected!');
});

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

这样做的好处

  • 模块化配置:通过将 Redis 配置提取到单独的文件中,你可以在应用的不同部分复用 Redis 连接。
  • 简化代码:在 app.js 中,你只需要关注业务逻辑,Redis 的连接和操作交由 redis.js 管理。
  • 易于维护:当 Redis 的配置变化时,只需要修改 redis.js 文件,而不必到处修改应用中的连接逻辑。

额外建议

  • 如果你的应用使用了多个模块或需要在多个地方访问 Redis,那么你可以通过将 Redis 客户端导出并在其他模块中引入它,从而在不同地方使用同一个 Redis 连接。

1. 使用第三方免费 Redis 服务

1.1 Upstash (免费版)

  • 官网: https://upstash.com/
  • 免费计划:
    • 每月最多 10,000 次请求。
    • 最大数据库大小为 256MB。
  • 适合场景:
    • 小型开发或测试环境。
    • Redis 用作缓存、验证码存储等轻量级应用。
  • 如何结合华为云
    • 在华为云的服务器上通过 ioredisnode-redis 等库连接到 Upstash 提供的 Redis 实例。

连接示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
javascript


Copy code
const Redis = require('ioredis');

const redis = new Redis({
host: 'upstash-redis-instance-url', // Upstash 提供的 Redis 实例 URL
port: 6379, // 默认 Redis 端口
password: 'your-password', // Upstash 提供的密码
tls: {} // 支持 TLS 连接
});

redis.set('key', 'value');
redis.get('key', (err, result) => {
if (err) console.error(err);
console.log('Redis result:', result);
});

1.2 Redis Labs (Redis Cloud)

  • 官网: https://redislabs.com/
  • 免费计划:
    • 提供 30MB 的免费 Redis 实例。
  • 适合场景:
    • 适合开发或小型项目。
    • 对于验证码、会话管理等小型缓存非常合适。
  • 如何结合华为云
    • 通过 Redis Labs 提供的 Redis 实例 URL 和认证信息,在华为云服务器上连接 Redis。

连接示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
javascript


Copy code
const Redis = require('ioredis');

const redis = new Redis({
host: 'your-redis-labs-url',
port: 6379,
password: 'your-redis-labs-password'
});

redis.set('key', 'value');
redis.get('key', (err, result) => {
if (err) console.error(err);
console.log('Redis result:', result);
});

1.3 Heroku Redis (免费版)

  • 官网: https://www.heroku.com/redis
  • 免费计划:
    • 提供 25MB 存储,适用于小型应用。
  • 适合场景:
    • 适合在 Heroku 部署的应用,或者其他小型开发/测试环境。
  • 如何结合华为云
    • 如果你在华为云上有 Node.js 后端应用,可以直接连接 Heroku 提供的 Redis 服务。

连接示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
javascript


Copy code
const Redis = require('ioredis');

const redis = new Redis({
host: 'heroku-redis-url', // Heroku 提供的 Redis 实例 URL
port: 6379,
password: 'heroku-redis-password' // 密码
});

redis.set('key', 'value');
redis.get('key', (err, result) => {
if (err) console.error(err);
console.log('Redis result:', result);
});

2. 在华为云本地自建 Redis(免费)

如果你不想依赖外部服务,可以选择 在华为云的服务器上自建 Redis。这将完全免费,但你需要自己管理 Redis 实例的部署、维护和安全配置。

步骤

  1. 选择云服务器:在华为云上创建一台云服务器,推荐选择轻量应用服务器(Lighthouse)或普通的 ECS 实例来托管 Redis。
  2. 安装 Redis: 在服务器上使用以下命令安装 Redis:
1
2
3
4
5
6
bash


Copy code
sudo apt update
sudo apt install redis-server
  1. 配置 Redis
    • 修改 /etc/redis/redis.conf 配置文件,确保 Redis 监听正确的 IP 地址。
    • 为 Redis 设置一个安全的密码。
  2. 启动 Redis 服务: 启动并使 Redis 开机自启:
1
2
3
4
5
6
bash


Copy code
sudo systemctl enable redis-server
sudo systemctl start redis-server
  1. 在 Node.js 应用中连接: 通过 ioredisnode-redis 在你的应用中连接本地 Redis:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
javascript


Copy code
const Redis = require('ioredis');

const redis = new Redis({
host: 'localhost', // Redis 主机地址
port: 6379, // Redis 默认端口
password: 'your-password' // 设置的密码(如果配置了的话)
});

redis.set('key', 'value');
redis.get('key', (err, result) => {
if (err) console.error(err);
console.log('Redis result:', result);
});

优点

  • 免费:无需付费。
  • 控制权:可以完全控制 Redis 配置和安全性。
  • 灵活性:适合处理大型数据和高流量需求。

缺点

  • 需要手动管理 Redis 实例的维护、扩展和高可用性。
  • 需要额外的运维工作,如定期备份、监控等。

3. 总结

  • 适合小型开发或测试环境:你可以选择 UpstashRedis LabsHeroku Redis,它们提供免费的 Redis 服务,适合小型项目或轻量级应用,并且容易集成到你的华为云服务器中。
  • 适合自建实例:如果你有一定的运维能力并且不介意管理 Redis,可以选择在华为云服务器上自行安装 Redis,完全免费,并能根据需求调整配置。

对于生产环境,如果 Redis 服务的需求逐渐增大,建议考虑付费版本以获得更多功能、支持和性能保障。