如何在 Redis 中设置键并获取值(我正在构建一个 url 缩短器)
How to set a key in Redis and get the value (I'm building a url shortener)
我是 Redis 的新手,我目前正在经历一个项目停滞不前,因为我不知道在 Redis 中 set
和 get
的任何其他方式。
我的问题是我正在构建一个 url 缩短器,当用户向服务器发布(一个 POST
请求)一个 url 时,我正在设置 url 作为键,nanoid 生成的代码作为值,并将 nanoid 代码发回给用户。但是当用户向服务器发送带有 url 代码的 GET
请求时,我必须检查 url 是否已经缓存并将用户重定向到 url 但我不能因为实际的 url 被设置为键而不是 url 代码所以它总是 return 未定义。你能帮我解决这个问题吗?还有其他人可以做到这一点吗?提前谢谢了!这是代码:
import redis from 'redis';
import http from 'http';
import express from 'express';
import { Router } from 'express';
import { promisify } from 'util';
import { nanoid } from 'nanoid';
interface Handler {
(req: Request, res: Response, next: NextFunction): Promise<void> | void;
}
interface Route {
path: string;
method: string;
handler: Handler | Handler[];
}
const { PORT = 8080} = process.env;
// I'm using a docker container
const { REDIS_URL = 'redis://cache:6379' } = process.env;
const redisClient = redis.createClient({
url: REDIS_URL
});
const initCache = async () =>
new Promise((resolve, reject) => {
redisClient.on('connect', () => {
console.log('Redis client connected');
resolve(redisClient);
});
redisClient.on('error', error => reject(error));
});
async function getShortenedURL(url: string) {
const urlCode = nanoid(7);
redisClient.setex(url, 3600, urlCode);
return urlCode;
}
const getAsync = promisify(redisClient.get).bind(redisClient);
async function getFromCache(key: string) {
const data = await getAsync(key);
return data;
}
const routes = [
{
path: '/:url',
method: 'get',
handler: [
async ({ params }: Request, res: Response, next: NextFunction) => {
try {
const { url } = params;
const result = await getFromCache(url);
if (result) {
res.redirect(301, result);
} else {
throw new Error('Invalid url');
}
} catch (error) {
console.error(error);
}
}
]
},
{
path: '/api/url',
method: 'post',
handler: [
async ({ body }: Request, res: Response, next: NextFunction) => {
const { url } = body;
const result = await getFromCache(url);
result ? res.status(200).send(`http://localhost:${PORT}/${result}`) : next();
},
async ({ body }: Request, res: Response) => {
const result = await getShortenedURL(body.url as string);
res.status(200).send(result);
}
]
}
];
const applyRoutes = (routes: Route[], router: Router) => {
for (const route of routes) {
const { method, path, handler } = route;
(router as any)[method](path, handler);
}
};
const router = express();
applyRoutes(routes, router);
const server = http.createServer(router);
async function start() {
await initCache();
server.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}...`)
}
);
}
start();
您应该使用为 URL 生成的 HashCode 作为字典的键,因为您打算稍后通过缩短的 URL 进行查找。
Post--> 散列 URL,根据长度限制的需要对其进行编码 return 缩短的密钥 URL 并放入 <Hash,URL>
在你的地图上
Get--> 用户给出缩短的键,字典查找缩短的键和 return 实际的 URL.
据我了解,您需要确保没有将任何给定的 url 缩短和存储两次。
您可以对 url 进行编码并将其同时用作排序版本和键。例如
www.someurltoshorten.com -> encoded value ->
{key: value} -> encoded value: www.someurltoshorten.com
如果用户想要缩短 url,您首先对其进行编码,您应该为完全相同的 url.
获得完全相同的哈希值
获得编码值后,您可以使用带有“GET”选项的SET 命令。您还可以使用过期 (EXAT) 选项使用 Redis 中内置的功能清理旧的 urls(那些没人再寻找的)。
它将为您执行以下操作:
设置键来保存字符串值(键是 url 的短版本,值是 url 本身)
如果该值存在,它将覆盖它并重置(延长)TTL(生存时间)(如果您设置了它)。
“GET”选项将 return 旧值(如果存在或为空)。
使用一条命令,您将能够:
- 在 Redis 中创建一个值
- 获取值(如果它已经存在)重置 TTL(扩展它是有意义的)并且所有这些都不需要任何额外的代码,只需一个命令!!!
流程可能如下所示:
- 用户输入一个url要缩短:
- 你编码 url
- 您使用 SET 命令将其存储在 Redis 中,其中键是编码值,值是 url。
- 你 return 你现在已经编码的值。无需检查 url 是否已经被缩短一次,因为 SET 命令将创建一个新条目或更新现有条目一次。
- 用户输入了一个缩短的url
- 你编码 url
- 您使用 SET 命令将其存储在 Redis 中,其中键是编码值,值是 url。
- 由于“GET”选项,您可以从 SET 命令 return 编辑的值中得到 url。
这两种情况的唯一区别在于你是 return 缩短的 url 还是正常的 url
基本上,您需要一个 Redis 命令才能完成所有这些工作。
我没有测试 url 的 encoding/hashing,它可能不适用于所有类型的 url。您需要检查哪种编码可以涵盖所有情况。
但这里的想法是概念本身。这类似于我们处理密码的方式。当您注册时,它会被散列。然后,当您登录并提供相同的密码时,我们可以再次对其进行哈希处理并比较哈希值。例如,使用 bycript 的安全散列可能很昂贵(可能需要很多时间)。
对于 url,您需要确保 encoding/hashing 对于相同的 url 总是产生相同的结果。
请记住此处描述的密钥长度 https://redis.io/topics/data-types-intro#redis-keys
我是 Redis 的新手,我目前正在经历一个项目停滞不前,因为我不知道在 Redis 中 set
和 get
的任何其他方式。
我的问题是我正在构建一个 url 缩短器,当用户向服务器发布(一个 POST
请求)一个 url 时,我正在设置 url 作为键,nanoid 生成的代码作为值,并将 nanoid 代码发回给用户。但是当用户向服务器发送带有 url 代码的 GET
请求时,我必须检查 url 是否已经缓存并将用户重定向到 url 但我不能因为实际的 url 被设置为键而不是 url 代码所以它总是 return 未定义。你能帮我解决这个问题吗?还有其他人可以做到这一点吗?提前谢谢了!这是代码:
import redis from 'redis';
import http from 'http';
import express from 'express';
import { Router } from 'express';
import { promisify } from 'util';
import { nanoid } from 'nanoid';
interface Handler {
(req: Request, res: Response, next: NextFunction): Promise<void> | void;
}
interface Route {
path: string;
method: string;
handler: Handler | Handler[];
}
const { PORT = 8080} = process.env;
// I'm using a docker container
const { REDIS_URL = 'redis://cache:6379' } = process.env;
const redisClient = redis.createClient({
url: REDIS_URL
});
const initCache = async () =>
new Promise((resolve, reject) => {
redisClient.on('connect', () => {
console.log('Redis client connected');
resolve(redisClient);
});
redisClient.on('error', error => reject(error));
});
async function getShortenedURL(url: string) {
const urlCode = nanoid(7);
redisClient.setex(url, 3600, urlCode);
return urlCode;
}
const getAsync = promisify(redisClient.get).bind(redisClient);
async function getFromCache(key: string) {
const data = await getAsync(key);
return data;
}
const routes = [
{
path: '/:url',
method: 'get',
handler: [
async ({ params }: Request, res: Response, next: NextFunction) => {
try {
const { url } = params;
const result = await getFromCache(url);
if (result) {
res.redirect(301, result);
} else {
throw new Error('Invalid url');
}
} catch (error) {
console.error(error);
}
}
]
},
{
path: '/api/url',
method: 'post',
handler: [
async ({ body }: Request, res: Response, next: NextFunction) => {
const { url } = body;
const result = await getFromCache(url);
result ? res.status(200).send(`http://localhost:${PORT}/${result}`) : next();
},
async ({ body }: Request, res: Response) => {
const result = await getShortenedURL(body.url as string);
res.status(200).send(result);
}
]
}
];
const applyRoutes = (routes: Route[], router: Router) => {
for (const route of routes) {
const { method, path, handler } = route;
(router as any)[method](path, handler);
}
};
const router = express();
applyRoutes(routes, router);
const server = http.createServer(router);
async function start() {
await initCache();
server.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}...`)
}
);
}
start();
您应该使用为 URL 生成的 HashCode 作为字典的键,因为您打算稍后通过缩短的 URL 进行查找。
Post--> 散列 URL,根据长度限制的需要对其进行编码 return 缩短的密钥 URL 并放入 <Hash,URL>
在你的地图上
Get--> 用户给出缩短的键,字典查找缩短的键和 return 实际的 URL.
据我了解,您需要确保没有将任何给定的 url 缩短和存储两次。
您可以对 url 进行编码并将其同时用作排序版本和键。例如
www.someurltoshorten.com -> encoded value ->
{key: value} -> encoded value: www.someurltoshorten.com
如果用户想要缩短 url,您首先对其进行编码,您应该为完全相同的 url.
获得完全相同的哈希值获得编码值后,您可以使用带有“GET”选项的SET 命令。您还可以使用过期 (EXAT) 选项使用 Redis 中内置的功能清理旧的 urls(那些没人再寻找的)。
它将为您执行以下操作:
设置键来保存字符串值(键是 url 的短版本,值是 url 本身)
如果该值存在,它将覆盖它并重置(延长)TTL(生存时间)(如果您设置了它)。
“GET”选项将 return 旧值(如果存在或为空)。
使用一条命令,您将能够:
- 在 Redis 中创建一个值
- 获取值(如果它已经存在)重置 TTL(扩展它是有意义的)并且所有这些都不需要任何额外的代码,只需一个命令!!!
流程可能如下所示:
- 用户输入一个url要缩短:
- 你编码 url
- 您使用 SET 命令将其存储在 Redis 中,其中键是编码值,值是 url。
- 你 return 你现在已经编码的值。无需检查 url 是否已经被缩短一次,因为 SET 命令将创建一个新条目或更新现有条目一次。
- 用户输入了一个缩短的url
- 你编码 url
- 您使用 SET 命令将其存储在 Redis 中,其中键是编码值,值是 url。
- 由于“GET”选项,您可以从 SET 命令 return 编辑的值中得到 url。
这两种情况的唯一区别在于你是 return 缩短的 url 还是正常的 url
基本上,您需要一个 Redis 命令才能完成所有这些工作。
我没有测试 url 的 encoding/hashing,它可能不适用于所有类型的 url。您需要检查哪种编码可以涵盖所有情况。
但这里的想法是概念本身。这类似于我们处理密码的方式。当您注册时,它会被散列。然后,当您登录并提供相同的密码时,我们可以再次对其进行哈希处理并比较哈希值。例如,使用 bycript 的安全散列可能很昂贵(可能需要很多时间)。
对于 url,您需要确保 encoding/hashing 对于相同的 url 总是产生相同的结果。
请记住此处描述的密钥长度 https://redis.io/topics/data-types-intro#redis-keys