如何在 Redis 中设置键并获取值(我正在构建一个 url 缩短器)

How to set a key in Redis and get the value (I'm building a url shortener)

我是 Redis 的新手,我目前正在经历一个项目停滞不前,因为我不知道在 Redis 中 setget 的任何其他方式。

我的问题是我正在构建一个 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(那些没人再寻找的)。

它将为您执行以下操作:

  1. 设置键来保存字符串值(键是 url 的短版本,值是 url 本身)

  2. 如果该值存在,它将覆盖它并重置(延长)TTL(生存时间)(如果您设置了它)。

  3. “GET”选项将 return 旧值(如果存在或为空)。

使用一条命令,您将能够:

  1. 在 Redis 中创建一个值
  2. 获取值(如果它已经存在)重置 TTL(扩展它是有意义的)并且所有这些都不需要任何额外的代码,只需一个命令!!!

流程可能如下所示:

  1. 用户输入一个url要缩短:
  • 你编码 url
  • 您使用 SET 命令将其存储在 Redis 中,其中键是编码值,值是 url。
  • 你 return 你现在已经编码的值。无需检查 url 是否已经被缩短一次,因为 SET 命令将创建一个新条目或更新现有条目一次。
  1. 用户输入了一个缩短的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