Bun Redis by secondsky/claude-skills
npx skills add https://github.com/secondsky/claude-skills --skill 'Bun Redis'使用流行的 Redis 客户端实现 Bun 与 Redis 的集成。
| 客户端 | 最佳适用场景 | 安装 |
|---|---|---|
ioredis | 自托管 Redis | bun add ioredis |
@upstash/redis | 无服务器/边缘计算 | bun add @upstash/redis |
redis | 官方 Node 客户端 | bun add redis |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
import Redis from "ioredis";
// 默认连接
const redis = new Redis();
// 带选项连接
const redis = new Redis({
host: "localhost",
port: 6379,
password: "secret",
db: 0,
});
// 连接字符串
const redis = new Redis("redis://:password@localhost:6379/0");
// TLS 连接
const redis = new Redis({
host: "redis.example.com",
port: 6380,
tls: {},
});
import Redis from "ioredis";
const redis = new Redis();
// 字符串
await redis.set("name", "Alice");
await redis.set("count", "100");
await redis.setex("temp", 60, "expires in 60s"); // 带 TTL
const name = await redis.get("name"); // "Alice"
const count = await redis.incr("count"); // 101
await redis.del("name");
// 检查存在性
const exists = await redis.exists("name"); // 0 或 1
// TTL
await redis.expire("key", 3600); // 设置 1 小时 TTL
const ttl = await redis.ttl("key"); // 获取剩余 TTL
// 设置哈希字段
await redis.hset("user:1", {
name: "Alice",
email: "alice@example.com",
age: "30",
});
// 获取单个字段
const name = await redis.hget("user:1", "name");
// 获取所有字段
const user = await redis.hgetall("user:1");
// { name: "Alice", email: "...", age: "30" }
// 递增字段
await redis.hincrby("user:1", "visits", 1);
// 添加到列表
await redis.rpush("queue", "task1", "task2");
await redis.lpush("queue", "urgent");
// 从列表弹出
const task = await redis.lpop("queue"); // "urgent"
const blocking = await redis.blpop("queue", 5); // 等待 5 秒
// 范围查询
const items = await redis.lrange("queue", 0, -1);
// 添加成员
await redis.sadd("tags", "javascript", "typescript", "bun");
// 检查成员资格
const isMember = await redis.sismember("tags", "bun"); // 1
// 获取所有成员
const tags = await redis.smembers("tags");
// 集合操作
await redis.sinter("tags1", "tags2"); // 交集
await redis.sunion("tags1", "tags2"); // 并集
// 带分数添加
await redis.zadd("leaderboard", 100, "alice", 200, "bob", 150, "charlie");
// 按排名获取
const top3 = await redis.zrevrange("leaderboard", 0, 2, "WITHSCORES");
// 按分数范围获取
const highScores = await redis.zrangebyscore("leaderboard", 100, 200);
// 递增分数
await redis.zincrby("leaderboard", 50, "alice");
// 需要 RedisJSON 模块
await redis.call("JSON.SET", "user:1", "$", JSON.stringify({
name: "Alice",
settings: { theme: "dark" },
}));
const user = await redis.call("JSON.GET", "user:1");
const settings = await redis.call("JSON.GET", "user:1", "$.settings");
import Redis from "ioredis";
// 发布者
const pub = new Redis();
// 订阅者
const sub = new Redis();
// 订阅频道
sub.subscribe("notifications", (err, count) => {
console.log(`已订阅 ${count} 个频道`);
});
// 处理消息
sub.on("message", (channel, message) => {
console.log(`${channel}: ${message}`);
});
// 发布
await pub.publish("notifications", JSON.stringify({
type: "alert",
message: "Hello!",
}));
// 模式订阅
sub.psubscribe("user:*");
sub.on("pmessage", (pattern, channel, message) => {
console.log(`${pattern} -> ${channel}: ${message}`);
});
// Multi/Exec
const results = await redis
.multi()
.set("key1", "value1")
.set("key2", "value2")
.incr("counter")
.exec();
// 管道(非原子性,性能更好)
const pipeline = redis.pipeline();
pipeline.set("key1", "value1");
pipeline.set("key2", "value2");
pipeline.incr("counter");
const results = await pipeline.exec();
import { Redis } from "@upstash/redis";
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
// 与 ioredis 相同的 API
await redis.set("key", "value");
const value = await redis.get("key");
// 自动 JSON 序列化
await redis.set("user", { name: "Alice", age: 30 });
const user = await redis.get<{ name: string; age: number }>("user");
async function getUser(id: string) {
// 检查缓存
const cached = await redis.get(`user:${id}`);
if (cached) {
return JSON.parse(cached);
}
// 从数据库获取
const user = await db.query.users.findFirst({
where: eq(users.id, id),
});
// 缓存 1 小时
if (user) {
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
}
return user;
}
async function updateUser(id: string, data: UserUpdate) {
// 更新数据库
await db.update(users).set(data).where(eq(users.id, id));
// 更新缓存
const user = await db.query.users.findFirst({
where: eq(users.id, id),
});
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
return user;
}
async function rateLimit(key: string, limit: number, window: number) {
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, window);
}
return current <= limit;
}
// 使用示例
const allowed = await rateLimit(`rate:${userId}`, 100, 60);
if (!allowed) {
throw new Error("超出速率限制");
}
import { Hono } from "hono";
import Redis from "ioredis";
import { v4 as uuid } from "uuid";
const redis = new Redis();
const app = new Hono();
app.use("*", async (c, next) => {
const sessionId = c.req.header("X-Session-Id") || uuid();
const session = await redis.hgetall(`session:${sessionId}`);
c.set("session", session);
c.set("sessionId", sessionId);
await next();
// 保存会话
const updatedSession = c.get("session");
if (Object.keys(updatedSession).length > 0) {
await redis.hset(`session:${sessionId}`, updatedSession);
await redis.expire(`session:${sessionId}`, 86400); // 24 小时
}
});
| 错误 | 原因 | 修复方法 |
|---|---|---|
ECONNREFUSED | Redis 未运行 | 启动 Redis 服务器 |
NOAUTH | 需要身份验证 | 提供密码 |
WRONGTYPE | 错误的数据类型 | 检查键类型 |
OOM | 内存不足 | 配置 maxmemory |
当需要以下内容时加载 references/clustering.md:
当需要以下内容时加载 references/lua-scripts.md:
每周安装次数
–
代码仓库
GitHub 星标数
93
首次出现时间
–
安全审计
Redis integration with Bun using popular Redis clients.
| Client | Best For | Install |
|---|---|---|
ioredis | Self-hosted Redis | bun add ioredis |
@upstash/redis | Serverless/Edge | bun add @upstash/redis |
redis | Official Node client | bun add redis |
import Redis from "ioredis";
// Default connection
const redis = new Redis();
// With options
const redis = new Redis({
host: "localhost",
port: 6379,
password: "secret",
db: 0,
});
// Connection string
const redis = new Redis("redis://:password@localhost:6379/0");
// TLS connection
const redis = new Redis({
host: "redis.example.com",
port: 6380,
tls: {},
});
import Redis from "ioredis";
const redis = new Redis();
// Strings
await redis.set("name", "Alice");
await redis.set("count", "100");
await redis.setex("temp", 60, "expires in 60s"); // With TTL
const name = await redis.get("name"); // "Alice"
const count = await redis.incr("count"); // 101
await redis.del("name");
// Check existence
const exists = await redis.exists("name"); // 0 or 1
// TTL
await redis.expire("key", 3600); // Set 1 hour TTL
const ttl = await redis.ttl("key"); // Get remaining TTL
// Set hash fields
await redis.hset("user:1", {
name: "Alice",
email: "alice@example.com",
age: "30",
});
// Get single field
const name = await redis.hget("user:1", "name");
// Get all fields
const user = await redis.hgetall("user:1");
// { name: "Alice", email: "...", age: "30" }
// Increment field
await redis.hincrby("user:1", "visits", 1);
// Add to list
await redis.rpush("queue", "task1", "task2");
await redis.lpush("queue", "urgent");
// Pop from list
const task = await redis.lpop("queue"); // "urgent"
const blocking = await redis.blpop("queue", 5); // Wait 5s
// Range
const items = await redis.lrange("queue", 0, -1);
// Add members
await redis.sadd("tags", "javascript", "typescript", "bun");
// Check membership
const isMember = await redis.sismember("tags", "bun"); // 1
// Get all members
const tags = await redis.smembers("tags");
// Set operations
await redis.sinter("tags1", "tags2"); // Intersection
await redis.sunion("tags1", "tags2"); // Union
// Add with scores
await redis.zadd("leaderboard", 100, "alice", 200, "bob", 150, "charlie");
// Get by rank
const top3 = await redis.zrevrange("leaderboard", 0, 2, "WITHSCORES");
// Get by score range
const highScores = await redis.zrangebyscore("leaderboard", 100, 200);
// Increment score
await redis.zincrby("leaderboard", 50, "alice");
// Requires RedisJSON module
await redis.call("JSON.SET", "user:1", "$", JSON.stringify({
name: "Alice",
settings: { theme: "dark" },
}));
const user = await redis.call("JSON.GET", "user:1");
const settings = await redis.call("JSON.GET", "user:1", "$.settings");
import Redis from "ioredis";
// Publisher
const pub = new Redis();
// Subscriber
const sub = new Redis();
// Subscribe to channel
sub.subscribe("notifications", (err, count) => {
console.log(`Subscribed to ${count} channels`);
});
// Handle messages
sub.on("message", (channel, message) => {
console.log(`${channel}: ${message}`);
});
// Publish
await pub.publish("notifications", JSON.stringify({
type: "alert",
message: "Hello!",
}));
// Pattern subscribe
sub.psubscribe("user:*");
sub.on("pmessage", (pattern, channel, message) => {
console.log(`${pattern} -> ${channel}: ${message}`);
});
// Multi/Exec
const results = await redis
.multi()
.set("key1", "value1")
.set("key2", "value2")
.incr("counter")
.exec();
// Pipeline (no atomicity, better performance)
const pipeline = redis.pipeline();
pipeline.set("key1", "value1");
pipeline.set("key2", "value2");
pipeline.incr("counter");
const results = await pipeline.exec();
import { Redis } from "@upstash/redis";
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
// Same API as ioredis
await redis.set("key", "value");
const value = await redis.get("key");
// With automatic JSON serialization
await redis.set("user", { name: "Alice", age: 30 });
const user = await redis.get<{ name: string; age: number }>("user");
async function getUser(id: string) {
// Check cache
const cached = await redis.get(`user:${id}`);
if (cached) {
return JSON.parse(cached);
}
// Fetch from database
const user = await db.query.users.findFirst({
where: eq(users.id, id),
});
// Cache for 1 hour
if (user) {
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
}
return user;
}
async function updateUser(id: string, data: UserUpdate) {
// Update database
await db.update(users).set(data).where(eq(users.id, id));
// Update cache
const user = await db.query.users.findFirst({
where: eq(users.id, id),
});
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
return user;
}
async function rateLimit(key: string, limit: number, window: number) {
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, window);
}
return current <= limit;
}
// Usage
const allowed = await rateLimit(`rate:${userId}`, 100, 60);
if (!allowed) {
throw new Error("Rate limit exceeded");
}
import { Hono } from "hono";
import Redis from "ioredis";
import { v4 as uuid } from "uuid";
const redis = new Redis();
const app = new Hono();
app.use("*", async (c, next) => {
const sessionId = c.req.header("X-Session-Id") || uuid();
const session = await redis.hgetall(`session:${sessionId}`);
c.set("session", session);
c.set("sessionId", sessionId);
await next();
// Save session
const updatedSession = c.get("session");
if (Object.keys(updatedSession).length > 0) {
await redis.hset(`session:${sessionId}`, updatedSession);
await redis.expire(`session:${sessionId}`, 86400); // 24h
}
});
| Error | Cause | Fix |
|---|---|---|
ECONNREFUSED | Redis not running | Start Redis server |
NOAUTH | Authentication required | Provide password |
WRONGTYPE | Wrong data type | Check key type |
OOM | Out of memory | Configure maxmemory |
Load references/clustering.md when:
Load references/lua-scripts.md when:
Weekly Installs
–
Repository
GitHub Stars
93
First Seen
–
Security Audits
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
107,800 周安装
MarsWaveAI TTS:文本转语音API,支持多说话人脚本与快速语音合成
640 周安装
AI代码安全审计工具 - 检测vibe-coding应用漏洞,防止数据泄露与API密钥被盗
653 周安装
Office转Markdown工具:Word/Excel/PPT/PDF一键转换,支持AI增强处理
651 周安装
AI小说写作助手 - 专业小说创作全流程支持,涵盖构思、角色设计、世界观构建与章节续写
669 周安装
钉钉文档API技能:知识库与文档自动化操作完整指南
662 周安装
Oracle到PostgreSQL迁移测试项目脚手架 - 集成测试基础设施搭建指南
671 周安装