如何使用 NestJS 在 NodeJS 中创建类型安全的 URL Shortener

作者选择了(https://www.brightfunds.org/funds/tech-education)作为 写给捐款计划的一部分的捐款。

介绍

URL,简称为 Uniform Resource Locator,是网页上一个独特资源的地址,因为一个URL是独一无二的,所以没有两个资源可以有相同的URL。

URL 的长度和复杂性会有所不同. 一个 URL 可能会短到 example.com或长到 http://llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.co.uk. 复杂的 URL 可能会很糟糕,导致搜索引擎优化(SEO)问题,并对营销计划产生负面影响。 URL 缩短器将长的 URL 转化为更短的 URL,并在使用短的 URL 时将用户重定向到原始的 URL。

在本教程中,您将使用 NestJS创建一个 URL 缩短器。 首先,您将在 服务中实现 URL 缩短和重定向逻辑。

前提条件

要遵循本教程,您将需要:

步骤一:准备你的发展环境

在此步骤中,您将设置所需的一切,以便开始实施您的 URL 缩短逻辑. 您将在全球范围内安装 NestJS,生成新的 NestJS 应用程序锅炉,安装依赖,并创建您的项目的模块,服务和控制器。

首先,如果您之前没有安装它,您将在全球范围内安装 Nest CLI. 您将使用此 CLI 生成您的项目目录和所需的文件。

1npm install -g @nestjs/cli

-g旗帜将在您的系统上全球安装Nest CLI。

您将看到以下结果:

1[secondary_label Output]
2...
3added 249 packages, and audited 250 packages in 3m
439 packages are looking for funding
5run npm fund for details
6found 0 vulnerabilities

然后,您将使用命令创建项目并生成必要的锅炉板启动文件:

1nest new URL-shortener

您将看到以下结果:

 1[secondary_label Output]
 2...
 3  We will scaffold your app in a few seconds..
 4
 5CREATE url-shortener/.eslintrc.js (631 bytes)
 6CREATE url-shortener/.prettierrc (51 bytes)
 7CREATE url-shortener/nest-cli.json (118 bytes)
 8CREATE url-shortener/package.json (2002 bytes)
 9CREATE url-shortener/README.md (3339 bytes)
10CREATE url-shortener/tsconfig.build.json (97 bytes)
11CREATE url-shortener/tsconfig.json (546 bytes)
12CREATE url-shortener/src/app.controller.spec.ts (617 bytes)
13CREATE url-shortener/src/app.controller.ts (274 bytes)
14CREATE url-shortener/src/app.module.ts (249 bytes)
15CREATE url-shortener/src/app.service.ts (142 bytes)
16CREATE url-shortener/src/main.ts (208 bytes)
17CREATE url-shortener/test/app.e2e-spec.ts (630 bytes)
18CREATE url-shortener/test/jest-e2e.json (183 bytes)
19
20? Which package manager would you   to use? (Use arrow keys)
21> npm
22  yarn
23  pnpm

选择npm

你会看到以下的输出:

 1[secondary_label Output]
 2√ Installation in progress... ☕
 3
 4🚀  Successfully created project url-shortener
 5👉  Get started with the following commands:
 6
 7$ cd url-shortener
 8$ npm run start
 9
10                          Thanks for installing Nest 🙏
11                 Please consider donating to our open collective
12                        to help us maintain this package.
13
14               🍷  Donate: https://opencollective.com/nest

转到您创建的项目目录:

1cd url-shortener

您将在此目录中运行所有后续命令。

注意:NestJS CLI在创建新项目时会创建app.controller.ts,app.controller.spec.tsapp.service.ts文件。

接下来,您将安装所需的依赖。

本教程需要使用 NodeJS 的默认包管理器 npm安装一些依赖性,所需依赖性包括 TypeORM, SQLite, Class-validator, Class-transformerNano-ID

TypeORM是一个对象关系地图器,可促进TypeScript应用程序和关系数据库之间的交互。由于NestJS专用的@nestjs/typeorm’包,这个ORM与NestJS无缝工作。

运行以下命令来安装 TypeORM 及其专用 NestJS 包:

1npm install @nestjs/typeorm typeorm

SQLite是一个实现小,快速,自含的SQL数据库引擎的库,您将使用这种依赖作为您的数据库来存储和检索缩短的URL。

运行以下命令来安装 SQLite:

1npm install sqlite3

class-validator包包含用于NestJS数据验证的装饰器,您将使用此依赖性与您的数据传输对象来验证向您的应用程序发送的数据。

运行以下命令来安装class-validator:

1npm install class-validator

class-transformer包允许您将普通对象转换为一个类的实例,反之亦然.您将使用这个依赖性与‘class-validator’一起使用,因为它不能单独工作。

运行以下命令来安装class-transformer:

1npm install class-transformer

Nano-ID是一个安全的, URL 友好的单一字符串 ID 生成器,您将使用这种依赖性来生成每个 URL 资源的单一 ID。

运行以下命令来安装 Nano-ID:

1npm install nanoid@^3.0.0

<$>[注] 注: Nano-ID 的版本高于 3.0.0 禁用了对 CommonJS 模块的支持. 此问题可能会导致应用程序中的错误,因为 TypeScript 编译器产生的 JavaScript 代码仍然使用 CommonJS 模块系统。

安装所需的依赖性后,您将使用 Nest CLI 生成项目的模块、服务和控制器,该模块将组织您的项目,服务将处理 URL 缩写器的所有逻辑,控制器将处理路线。

运行以下命令来生成您的模块:

1nest generate module url

您将看到以下结果:

1[secondary_label Output]
2CREATE src/url/url.module.ts (80 bytes)
3UPDATE src/app.module.ts (304 bytes)

接下来,运行以下命令来生成您的服务:

1nest generate service url --no-spec

「--no-spec」的旗帜告诉Nest CLI在没有测试文件的情况下生成文件,您不需要本教程中的测试文件。

您将看到以下结果:

1[secondary_label Output]
2CREATE src/url/url.service.ts (87 bytes)
3UPDATE src/url/url.module.ts (151 bytes)

然后运行以下命令来生成您的控制器:

1nest generate controller url --no-spec

您将看到以下结果:

1[secondary_label Output]
2CREATE src/url/url.controller.ts (95 bytes)
3UPDATE src/url/url.module.ts (233 bytes)

在此步骤中,您生成了您的应用程序和开发所需的大部分文件,然后将您的应用程序连接到数据库。

步骤 2 – 将应用程序连接到数据库

在此步骤中,您将创建一个实体来模拟数据库中的 URL 资源. entity 是一个包含存储数据所需属性的文件。

使用nano或您偏好的文本编辑器,创建并打开名为url.entity.tssrc/url文件夹中的文件:

1nano src/url/url.entity.ts

此文件将包含模型您的数据的实体。

接下来,在您的 src/url/url.entity.ts 文件中,添加以下 Typescript 代码:

 1[label src/url/url.entity.ts]
 2import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
 3
 4@Entity()
 5export class Url {
 6    @PrimaryGeneratedColumn()
 7    id: number;
 8
 9    @Column()
10    urlCode: string;
11
12    @Column()
13    longUrl: string;
14
15    @Column()
16    shortUrl: string;
17}

首先,您从typeorm中导入实体PrimaryGeneratedColumn的装饰。

该代码创建并导出一个类URL,注明与实体装饰器标记一个类为实体。

每个属性都被指定并注明了相应的装饰器:ID的PrimaryGeneratedColumn和其他属性的ColumnPrimaryGeneratedColumn是一个装饰器,自动生成它注释的属性的值。

应该存储在数据库中的属性包括:

  • id 是数据库表的主要密钥。 * urlCode 是由 nanoid 包生成的独特 ID,将用于识别每个 URL。

保存并关闭文件。

接下来,您将创建应用程序和数据库之间的连接。

首先,在nano或您喜爱的文本编辑器中打开src/app.module.ts:

1nano src/app.module.ts

然后,将突出的行添加到文件中:

 1[label src/app.module.ts]
 2import { Module } from '@nestjs/common';
 3import { TypeOrmModule } from '@nestjs/typeorm';
 4import { Url } from './url/url.entity';
 5import { UrlModule } from './url/url.module';
 6
 7@Module({
 8  imports: [
 9    TypeOrmModule.forRoot({
10      type: 'sqlite',
11      database: 'URL.sqlite',
12      entities: [Url],
13      synchronize: true,
14    }),
15    UrlModule,
16  ],
17  controllers: [],
18  providers: [],
19})
20export class AppModule {}

首先,从@nestjs/typeorm导入TypeOrmModuleUrl./url/url.entity。你仍然可能有与AppControllerAppService相关的行。

在导入数组中,在TypeOrmModule上调用forRoot方法来通过应用程序中的所有模块共享连接。

配置对象包含创建连接的属性. 这些属性包括以下内容:

*类型属性表示您正在使用 TypeOrm 进行交互的数据库类型。在这种情况下,它被设置为sqlite。 *数据库属性表示数据库的偏好名称。在这种情况下,它被设置为URL.sqlite。 *实体属性是项目中的所有实体的组合。

注意: ** 将同步设置为仅在开发环境中是理想的。

保存并关闭文件。

接下来,您将创建一个存储库,作为应用程序和数据库之间的访问层,您需要将实体连接到其母模块,并且这种连接允许Nest和TypeOrm自动创建一个存储库。

打开src/url/url.module.ts:

1nano src/url/url.module.ts

在现有文件中,添加突出的行:

 1[label src/url/url.module.ts]
 2import { Module } from '@nestjs/common';
 3import { UrlService } from './url.service';
 4import { UrlController } from './url.controller';
 5import { TypeOrmModule } from '@nestjs/typeorm';
 6import { Url } from './url.entity';
 7
 8@Module({
 9  imports: [TypeOrmModule.forFeature([Url])],
10  providers: [UrlService],
11  controllers: [UrlController],
12})
13export class UrlModule {}

您在模块装饰器中创建一个导入数组,在那里您从@nestjs/typeorm导入TypeOrmModuleUrl./url.entity

保存并关闭文件。

Nest 和 TypeOrm 将创建一个幕后存储库,作为服务和数据库之间的访问层。

在此步骤中,您已将应用程序连接到数据库,现在您已准备好实现 URL 缩短逻辑。

步骤三:实施服务逻辑

在此步骤中,您将用两种方法实现您的服务逻辑。第一个方法,‘shortenUrl’,将包含所有URL缩写逻辑。第二种方法,‘redirect’,将包含所有逻辑来将用户重定向到原始URL。

提供服务访问存储库

在实施这些方法之前,您将为您的服务提供存储库访问权限,以便您的应用程序能够在数据库中阅读和写入数据。

首先,打开src/url/url.service.ts:

1nano src/url/url.service.ts

将以下突出的行添加到现有文件中:

 1[label src/url/url.service.ts]
 2import { Injectable } from '@nestjs/common';
 3import { Repository } from 'typeorm';
 4import { InjectRepository } from '@nestjs/typeorm';
 5import { Url } from './url.entity';
 6
 7@Injectable()
 8export class UrlService {
 9  constructor(
10    @InjectRepository(Url)
11    private repo: Repository<Url>,
12  ) {}
13}

您从typeorm导入Repository,从@nestjs/typeorm导入InjectRepository,从./url.entity导入Url

在你的UrlService类中,你创建一个constructor。在constructor内部,你宣布一个私有变量,repo,作为参数。然后,你将一个类型的Repository分配给repo用一个通用类型的Url

保存并关闭文件。

您的服务现在可以通过repo变量访问您的存储库,所有数据库查询和TypeOrm方法将被调用。

接下来,您将创建一个非同步的方法,即shortenUrl。该方法将采取一个URL作为论点,并返回一个缩短的URL。

创建数据传输对象

在创建非同步方法之前,您将创建 shortenUrl async 方法所需的数据传输对象. data-transfer object 是定义如何在应用程序之间发送数据的对象。

首先,在您的URL文件夹中创建一个dtos(数据传输对象)文件夹:

1mkdir src/url/dtos

然后,在该文件夹中创建一个名为url.dto.ts的文件:

1nano src/url/dtos/url.dto.ts

将以下代码添加到新文件中:

1[label src/url/dto/url.dto.ts]
2import { IsString, IsNotEmpty } from 'class-validator';
3
4export class ShortenURLDto {
5  @IsString()
6  @IsNotEmpty()
7  longUrl: string;
8}

您从类验证器导入IsStringIsNotEmpty装饰器,然后创建并导出ShortenURLDto类。

您还会用IsStringIsNotEmpty装饰符标注longUrl属性,并且使用这些装饰符标注longUrl属性将确保longUrl始终是一个字符串,而不是空。

保存并关闭文件。

然后,打开您的src/main.ts文件:

1nano src/main.ts

将突出的代码添加到现有文件中:

 1[label src/main.ts]
 2import { NestFactory } from '@nestjs/core';
 3import { AppModule } from './app.module';
 4import { ValidationPipe } from '@nestjs/common';
 5
 6async function bootstrap() {
 7  const app = await NestFactory.create(AppModule);
 8  app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
 9  await app.listen(3000);
10}
11bootstrap();

您导入验证管,它使用类验证器包来执行验证规则对所有进入您的应用程序的数据。

然后,您在您的应用程序实例(应用)上调用useGlobalPipes方法,并将一个ValidationPipe实例传递给一个选项对象,其中whitelist属性设置为trueuseGlobalPipes方法将ValidationPipe绑定到应用程序级别,确保所有路径都免受错误的数据。

保存并关闭文件。

接下来,您将将数据传输对象导入到url.service.ts文件中,并将其应用到shortenUrl方法。

创建shortenUrl方法

shortenUrl方法将处理大部分的URL缩短逻辑,它将采用类型的ShortenURLDto的参数url

首先,打开您的src/url/url.service.ts文件:

1nano src/url/url.service.ts

将突出的行添加到文件中:

 1[label src/url/url.service.ts]
 2import {
 3  BadRequestException,
 4  Injectable,
 5  NotFoundException,
 6  UnprocessableEntityException,
 7} from '@nestjs/common';
 8import { Repository } from 'typeorm';
 9import { InjectRepository } from '@nestjs/typeorm';
10import { Url } from './url.entity';
11import { ShortenURLDto } from './dtos/url.dto';
12import { nanoid } from 'nanoid';
13import { isURL } from 'class-validator';
14...

首先,您将从@nestjs/common导入NotFoundExeception,BadRequestExceptionUnprocessableEntityException,因为您将使用它们来处理错误。然后,您将从nanoid导入{nanoid},从class-validator导入isURL

然后,在constructor下方添加以下内容到UrlService类:

1[label src/url/url.service.ts]
2...
3async shortenUrl(url: ShortenURLDto) {}

然后,将以下代码添加到您的shortenUrl方法:

 1[label src/url/url.service.ts]
 2...
 3    const { longUrl } = url;
 4
 5    //checks if longurl is a valid URL
 6    if (!isURL(longUrl)) {
 7      throw new BadRequestException('String Must be a Valid URL');
 8    }
 9
10    const urlCode = nanoid(10);
11    const baseURL = 'http://localhost:3000';
12
13    try {
14      //check if the URL has already been shortened
15      let url = await this.repo.findOneBy({ longUrl });
16      //return it if it exists
17      if (url) return url.shortUrl;
18
19      //if it doesn't exist, shorten it
20      const shortUrl = `${baseURL}/${urlCode}`;
21
22      //add the new record to the database
23      url = this.repo.create({
24        urlCode,
25        longUrl,
26        shortUrl,
27      });
28
29      this.repo.save(url);
30      return url.shortUrl;
31    } catch (error) {
32      console.log(error);
33      throw new UnprocessableEntityException('Server Error');
34    }

在上面的代码块中,longUrl被从url对象中解构出来,然后,使用isURL方法,一个检查会验证longUrl是否是一个有效的URL。

使用nanoid生成一个urlCode。默认情况下,nanoid生成一个独特的二十一个字符串。 将所需的长度作为一个论点来排除默认行为。

然后,定义了基础 URL. 基础 URL 是您的网站地址的一致根。 在开发中,它是您的本地主机服务器;在生产中,它是您的域名。

一个试捕块将容纳所有代码与数据库进行交互,以便处理错误。

将 URL 缩短两次可能会导致数据重复,因此在数据库中运行搜索查询,以查看 URL 是否存在. 如果 URL 存在,则将返回其 shortUrl;否则,代码将继续缩短它.如果数据库中没有 URL 记录,则通过将 baseURLurlCode' 连接来创建一个短 URL。

然后,使用urlCode,longUrlshortUrl创建一个url实例。将url实例保存到数据库中,通过在repo上调用save方法并将该实例作为一个参数。

最后,如果出现错误,错误将登录到捕获区块中的控制台,并将投放一个UnprocessableEntityException消息。

现在你的url.service.ts文件将是这样的:

 1[label src/url/url.service.ts]
 2import {
 3  BadRequestException,
 4  Injectable,
 5  NotFoundException,
 6  UnprocessableEntityException,
 7} from '@nestjs/common';
 8import { Repository } from 'typeorm';
 9import { InjectRepository } from '@nestjs/typeorm';
10import { Url } from './url.entity';
11import { ShortenURLDto } from './dtos/url.dto';
12import { nanoid } from 'nanoid';
13import { isURL } from 'class-validator';
14
15@Injectable()
16export class UrlService {
17  constructor(
18    @InjectRepository(Url)
19    private repo: Repository<Url>,
20  ) {}
21
22  async shortenUrl(url: ShortenURLDto) {
23    const { longUrl } = url;
24
25    //checks if longurl is a valid URL
26    if (!isURL(longUrl)) {
27      throw new BadRequestException('String Must be a Valid URL');
28    }
29
30    const urlCode = nanoid(10);
31    const baseURL = 'http://localhost:3000';
32
33    try {
34      //check if the URL has already been shortened
35      let url = await this.repo.findOneBy({ longUrl });
36      //return it if it exists
37      if (url) return url.shortUrl;
38
39      //if it doesn't exist, shorten it
40      const shortUrl = `${baseURL}/${urlCode}`;
41
42      //add the new record to the database
43      url = this.repo.create({
44        urlCode,
45        longUrl,
46        shortUrl,
47      });
48
49      this.repo.save(url);
50      return url.shortUrl;
51    } catch (error) {
52      console.log(error);
53      throw new UnprocessableEntityException('Server Error');
54    }
55  }
56}

保存檔案

在这里,您设置了URL缩短逻辑的第一部分,接下来,您将在您的服务中实施重定向方法。

创建重定向方法

重定向方法将包含将用户重定向到长URL的逻辑。

src/url/url/service.ts文件中,将以下代码添加到您的UrlService类底部,以实现重定向方法:

 1[label src/url/url.service.ts]
 2...
 3  async redirect(urlCode: string) {
 4    try {
 5      const url = await this.repo.findOneBy({ urlCode });
 6      if (url) return url;
 7    } catch (error) {
 8      console.log(error);
 9      throw new NotFoundException('Resource Not Found');
10    }
11  }

重定向方法将urlCode作为参数,并尝试在数据库中找到与urlCode匹配的资源。

您的完成的url.service.ts文件现在将看起来像这样:

 1[label src/url/url.service.ts]
 2import {
 3  BadRequestException,
 4  Injectable,
 5  NotFoundException,
 6  UnprocessableEntityException,
 7} from '@nestjs/common';
 8import { Repository } from 'typeorm';
 9import { InjectRepository } from '@nestjs/typeorm';
10import { Url } from './url.entity';
11import { ShortenURLDto } from './dtos/url.dto';
12import { nanoid } from 'nanoid';
13import { isURL } from 'class-validator';
14
15@Injectable()
16export class UrlService {
17  constructor(
18    @InjectRepository(Url)
19    private repo: Repository<Url>,
20  ) {}
21
22  async shortenUrl(url: ShortenURLDto) {
23    const { longUrl } = url;
24
25    //checks if longurl is a valid URL
26    if (!isURL(longUrl)) {
27      throw new BadRequestException('String Must be a Valid URL');
28    }
29
30    const urlCode = nanoid(10);
31    const baseURL = 'http://localhost:3000';
32
33    try {
34      //check if the URL has already been shortened
35      let url = await this.repo.findOneBy({ longUrl });
36      //return it if it exists
37      if (url) return url.shortUrl;
38
39      //if it doesn't exist, shorten it
40      const shortUrl = `${baseURL}/${urlCode}`;
41
42      //add the new record to the database
43      url = this.repo.create({
44        urlCode,
45        longUrl,
46        shortUrl,
47      });
48
49      this.repo.save(url);
50      return url.shortUrl;
51    } catch (error) {
52      console.log(error);
53      throw new UnprocessableEntityException('Server Error');
54    }
55  }
56
57  async redirect(urlCode: string) {
58    try {
59      const url = await this.repo.findOneBy({ urlCode });
60      if (url) return url;
61    } catch (error) {
62      console.log(error);
63      throw new NotFoundException('Resource Not Found');
64    }
65  }
66}

保存并关闭文件。

您的 URL 缩短逻辑现在完成了两种方法:一种是缩短 URL,另一种是将缩短 URL 重定向到原始 URL。

在下一步中,您将在控制器类中实现这两种方法的路由处理器。

步骤 4 – 实施控制器逻辑

在此步骤中,您将创建两个路由处理器:一个POST路由处理器来处理缩短请求和一个GET路由处理器来处理重定向请求。

在部署控制器类中的路由之前,您必须向控制器提供该服务。

首先,打开您的src/url/url.controller.ts文件:

1nano src/url/url.controller.ts

将突出的行添加到文件中:

1[label src/url/url.controller.ts]
2import { Controller } from '@nestjs/common';
3import { UrlService } from './url.service';
4
5@Controller('url')
6export class UrlController {
7  constructor(private service: UrlService) {}
8}

首先,您将UrlService./url.service导入,然后,在控制器类中,您声明一个构建器,并将一个私有变量服务作为参数。

控制器设计器目前有一个字符串,url作为一个论点,这意味着控制器只会处理到localhost/3000/url/route的请求。这种行为会引入您的 URL 缩短逻辑中的错误,因为缩短的 URL 包含一个基础 url(localhost:3000)和一个 URL 代码(wyt4_uyP-Il),这些请求将组成一个新的 URL(localhost:3000/wyt4_uyP-Il).因此,这个控制器无法处理请求,而缩短的链接将返回一个404 Not Found错误。

删除url参数后,您的UrlController将是这样的:

1[label src/url/url.controller.ts]
2@Controller()
3export class UrlController {
4  constructor(private service: UrlService) {}
5}

src/url/url.controller.ts文件中,将突出的项目添加到进口声明中:

1[label src/url/url.controller.ts]
2import { Body, Controller, Get, Param, Post, Res } from '@nestjs/common';
3import { UrlService } from './url.service';
4import { ShortenURLDto } from './dtos/url.dto';

您从@nestjs/commonShortenURLDto./dtos/url.dto中导入Body,Get,Param,PostRes

然后将下列行添加到Constructor下面的UrlController,以定义POST路径处理器:

1[label src/url/url.controller.ts]
2...
3  @Post('shorten')
4  shortenUrl(
5    @Body()
6    url: ShortenURLDto,
7  ) {
8    return this.service.shortenUrl(url);
9  }

您创建了一个方法 shortenUrl,它使用一个词汇符号 url 和一个类型的 ShortenURLDto. 您使用 Body 装饰器注释 url 以从请求对象中提取身体对象,并填充 url 变量与其值。

然后,您使用邮件装饰器对整个方法进行注释,并将缩短作为参数。 此处理器将处理所有发送到Localhost:<port>/shorten的邮件请求。

接下来,在POST路线下方添加以下行,以定义重定向的GET路线处理器:

 1[label src/url/url.controller.ts]
 2...
 3  @Get(':code')
 4  async redirect(
 5    @Res() res,
 6    @Param('code')
 7    code: string,
 8  ) {
 9    const url = await this.service.redirect(code);
10
11    return res.redirect(url.longUrl);
12  }

您创建一个有两个参数的重定向方法:res,用Res装饰器注释,和代码,用Param装饰器注释。Res装饰器(https://docs.nestjs.com/controllers# routing)将它注释的类转化为 Express 响应对象,允许您使用图书馆特定的命令,如Express装置。

您使用Get装饰器注明重定向方法,并传递一个野卡参数:代码 然后将代码作为参数传递给Param装饰器。

然后在服务上调用重定向方法,等待结果,并将其存储在变量中,即url

最后,您返回res.redirect()并将url.longUrl作为参数,该方法将处理GET请求到localhost:<port>/code,或您的缩短的URL。

您的「src/url/url.controller.ts」文件现在将看起来像这样:

 1[label src/url/url.controller.ts]
 2import { Body, Controller, Get, Param, Post, Res } from '@nestjs/common';
 3import { UrlService } from './url.service';
 4import { ShortenURLDto } from './dtos/url.dto';
 5
 6@Controller()
 7export class UrlController {
 8  constructor(private service: UrlService) {}
 9
10  @Post('shorten')
11  shortenUrl(
12    @Body()
13    url: ShortenURLDto,
14  ) {
15    return this.service.shortenUrl(url);
16  }
17
18  @Get(':code')
19  async redirect(
20    @Res() res,
21    @Param('code')
22    code: string,
23  ) {
24    const url = await this.service.redirect(code);
25
26    return res.redirect(url.longUrl);
27  }
28}

保存并关闭文件。

现在你已经定义了你的POSTGET路由处理器,你的URL缩短器是完全功能的。

步骤 5 – 测试 URL 缩短器

在此步骤中,您将测试您在上一个步骤中定义的 URL 缩短器。

首先,启动您的应用程序,运行:

1npm run start

您将看到以下结果:

 1[secondary_label Output]
 2[Nest] 12640  - 06/08/2022, 16:20:04 LOG [NestFactory] Starting Nest application...
 3[Nest] 12640  - 06/08/2022, 16:20:07 LOG [InstanceLoader] AppModule dependencies initialized +2942ms
 4[Nest] 12640  - 06/08/2022, 16:20:07 LOG [InstanceLoader] TypeOrmModule dependencies initialized +1ms
 5[Nest] 12640  - 06/08/2022, 16:20:08 LOG [InstanceLoader] TypeOrmCoreModule dependencies initialized +257ms
 6[Nest] 12640  - 06/08/2022, 16:20:08 LOG [InstanceLoader] TypeOrmModule dependencies initialized +2ms
 7[Nest] 12640  - 06/08/2022, 16:20:08 LOG [InstanceLoader] UrlModule dependencies initialized +4ms
 8[Nest] 12640  - 06/08/2022, 16:20:08 LOG [RoutesResolver] UrlController {/}: +68ms
 9[Nest] 12640  - 06/08/2022, 16:20:08 LOG [RouterExplorer] Mapped {/shorten, POST} route +7ms
10[Nest] 12640  - 06/08/2022, 16:20:08 LOG [RouterExplorer] Mapped {/:code, GET} route +2ms
11[Nest] 12640  - 06/08/2022, 16:20:08 LOG [NestApplication] Nest application successfully started +7ms

打开一个新的终端,使用‘curl’或您喜爱的API测试工具,向‘http://localhost:3000/shorten’发出‘POST’请求,其中包含下面的数据或您所选择的任何数据。

运行此命令以创建样本POST请求:

1[environment second]
2curl -d "{\"longUrl\":\"http://llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.co.uk\"}" -H "Content-Type: application/json" http://localhost:3000/shorten

-d旗记录了HTTP POST请求数据,而-H旗则为HTTP请求设置了标题。

您将收到一个短的 URL 作为回复,例如下面的示例:

1[environment second]
2http://localhost:3000/MWBNHDiloW

最后,复制短的URL并将链接粘贴到您的浏览器中,然后按ENTER

结论

在本文中,您使用 NestJS 创建了一个 URL 缩写器. 如果您添加了 前端接口,您可以将其部署用于公共用途。

NestJS 提供类型安全和架构,使您的应用程序更安全,可维护和可扩展。 有关更多信息,请访问 NestJS 官方文档

Published At
Categories with 技术
comments powered by Disqus