


NestJS 提供了多种预设的错误类,这些错误类对应于常见的 HTTP 状态码,并在 @nestjs/common 包中。BadRequestException: 对应于状态码 400(Bad Request),表明客户端请求的语法错误或无法处理请求。UnauthorizedException: 对应于状态码 401(Unauthorized),表明请求需要用户的身份认证。NotFoundException: 对应于状态码 404(Not Found),表明服务器找不到请求的资源。ForbiddenException: 对应于状态码 403(Forbidden),表明服务器理解请求但拒绝...
前言Nestjs文档中有两种鉴权方式,一种是自定义一个守卫,在守卫中自己从上下文header中取出token信息,然后自己解析判定。import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { jwtConstants } from './constants'; import { Request...
前言jwt生成,nestjs官方有一个专门的库@nestjs/jwt,它是一个模块,我们只需要将他注册为全局模块,并且传入secret密匙就能直接去使用它的服务了。教程先安装依赖:pnpm i @nestjs/jwt在app.module.ts中引入该模块,通过useFactory工厂模式,获取到ConfigModule提供的ConfigService服务,从而拿到环境变量文件中配置的secret。.env.development在环境变量中配置TOKEN_SECRET# token-secret TOKEN_SECRET="xxxxx"注意不要泄露这个密匙。app....
简介所有的数据库中,对密码的保存永远不是明文的,这是一种常识,我们使用Nestjs和Prisma创建用户时也是一样的,对用户的密码也不是明文的。有些教程使用argon2库来加密密码,但是这个库在windows上永远是安装失败,为此直接放弃使用它,改用crypto-js,来实现相同功能。教程先安装依赖:pnpm i crypto-js @types/crypto-js然后我们封装一个简单的工具文件:md5.tsimport { MD5 } from "crypto-js"; /** * @description: hash加密 * @param {string} ...
前言一个很经典的业务需求,注册用户时需要判断用户的账号是否已经存在,登录的时候也需要判断用户是否存在,只不过一个需要存在时报错,另一个需要判断不存在时报错。教程官方文档:class-validator创建文件:IsFieldExist.tsimport { registerDecorator, ValidationOptions, ValidationArguments } from "class-validator"; import { PrismaClient } from "@prisma/client"; let prisma: Pris...
前言默认情况下class-validator这个库本身并没有提供二次密码校验的方式,所以我们需要自己去实现这个功能,那么自然是需要实现一个符合库规范的属性装饰器了。首先我们需要知道,在class-validator中,自己实现一个校验方式,是可以获取到校验对象的,既然可以获取到校验的对象,自然可以读取对象里的那些属性了,为此实现一个二次密码校验是非常简单的。教程假设我们的数据对象如下:{ name: "", password: "", confirmPassword: "" }我们需要判断confirmPasswor...
简介在学习使用Nsetjs中了解了DTO这个东西,但是作为一个前端开发人员,其实不太懂这个东西是干什么的,于是自己去了解了一些,并记录一下。什么是DTO?nestjs框架本身借鉴了很多后端框架的经验,其中DTO就是一种在java开发广泛使用的一种设计模式。DTO的全称是Data Transfer Object,是一个用于客户端与后端服务传输数据的一种对象形式,在nestjs中更细节一点,就是前端传输的数据会在Controller控制层使用前,被转换成DTO数据对象,其实就是class类通过一些方式将数据赋值到这个类的实例对象上。后续的操作读取其实都是使用的DTO对象,同时我们的数据校验也...
前言在nestjs中,我们在controller或者在service中去调用一些依赖,不是像写vue那种,直接es6导入导出,而是通过依赖注入的形式,在类构造函数constructor中声明需要的依赖,nestjs会在实例化的时候将对应的依赖实例作为参数传入。示例:app.controller.tsimport { Controller, Get } from "@nestjs/common"; import { AppService } from "./app.service"; @Controller() export class AppCo...
前言在一个稍微正式点的项目中,它的环境变量文件肯定多个的,一般会有开发用的环境变量文件,正式上线的环境变量文件,测试用的环境变量文件,甚至还有更多,但是在nestjs和prisma的官方文档中,都是只用一个环境变量文件.env,显然有点弱了,为此写一篇关于如何使用多环境变量文件的教程。依赖安装pnpm i cross-env dotenv dotenv-cli -D理论上讲dotenv可以不用明确安装,但是但是安装一些,以后也用得到,比较是一个基建类的库,用于解决环境变量相关方面。cross-env 用于指定NODE_ENV。dotenv-cli是给prisma用的。创建环境变量文件在项...
前言在一些练习demo中,我们常常会使用cli工具去创建一个项目,不管这个项目是前端还是后端的,大部分情况都会顺带帮你初始化一个本地的git仓库,有的时候倒是无所谓,但是有时候我们可能需要将这个demo项目上传到远程仓库上去。比较费事的做法就是先在远程仓库管理里创建我们需要的git仓库,然后本地拉取,再将demo文件cv过去,再上传。有点麻烦,其实我们可以通过简单的命令将远程仓库地址直接关联到本地上去,这样我们就可以不需要cv操作了。教程我们先在远程创建我们的自己的仓库地址,假设地址为:https://gitee.com/ssss/sss.git。我们进入到demo项目,输入命令:git...
前言最近发现这个很有意思的配置,可以让项目中强制使用指定的包管理器,其他人瞎鸡儿用的话就会报错阻止,这个配置其实在pnpm的官方文档里就有,只是一直都没发现。这里贴一下出处:Only allow pnpm下面开始教程。教程在开始之前我们需要了解一下,npm在安装包的时候其实是有一些预设的生命周期脚本的,当然这些脚本其实就是package.json中的scripts定义的命令,官方预设了一些名字,当你添加对应的脚本名字和内容的时候,npm会在install的生命周期中去运行对应时机的脚本命令。生命周期文档:npm-install示例:{ "scripts": {...
前言有的时候我们在并行开发一些内容的时候,会遇到需要将两个版本打平的情况,比如将a分支的内容全部替换到b上,以它为基础再进行开发。此时我们的b分支已经不需要自己之前开发的哪些内容,我的做法就是完全替换,git 的提交记录也没有了,省的文件冲突了。教程我们先切换到需要被覆盖的分支b:git checkout b然后通过reset命令进行重置:git reset --hard a如果你是首次拉取的仓库,那么a分支可能需要替换成:origin/a此时b分支的内容全部被覆盖了,理论上不需要再提交到远程仓库的,不过以防万一还是补一下:git push -f origin b其他做法方式有很多,这里...
前言最近发现动态去拼接资源路径还是挺常用的,于是把我之前封装的hooks单独分享出来。教程useAssets.tsexport function useAssets() { /** 前缀补路径斜杠 */ // eslint-disable-next-line @typescript-eslint/no-unused-vars function addPrefixSlash(path: string) { return path.startsWith("/") ? path : `/${path}`; } /** ...
前言这段时间对接了下web版的谷歌登录,总体来说坑非常多,即便到现在,我都感觉这个教程都只能算是一个应急处理方案,并不完美,缺点如下:文档稀少,官方提供的教程自由度很差ui不可控,前端无法自定义触发按钮不多说,开搞!教程官方文档和流程官方文档:web谷歌登录流程:我们需要先去将需要web登录的域名去向谷歌申请一个客户端id,用于在客户端登录处理。申请地址:开发者后台创建凭据 --- 选择OAuth 客户端ID --- 应用类型选择 web应用 --- 自己填写一个名称已获授权的 JavaScript 来源这个选项意思就是你允许使用这个客户端id对应的网站域名,添加对应的网站地址,个人测试...
前言在pinia中使用setup语法是非常舒服的一件事情,但是也会有一些坑点,其中就是当我们使用store.$reset()进行重置的时候会发生报错:Store "xxxx" is built using the setup syntax and does not implement $reset()意思是$reset并没有实现,我们需要自己手动实现这个。教程解决办法我是从stackoverflow看到的,这里放出出处:《Pinia: $reset alternative when using setup syntax》我们需要创建一个插件去实现这个功能:stores...
前言一直很想体验下websocket,苦于一直没有机会,乘着这次优化,封装了一个原生的websocket处理类,本来是想用Socket.io的,但是它只能和它配套的server端使用,对于一些非封装的服务端,没法直接使用,于是只能自己封装了。功能:支持失败重连支持心跳支持重新初始化事件订阅ts愉悦的类型推断,传入事件名和回调函数,能自动推断出结果类型支持手动断卡,重新初始化即可重新连接为什么需要重新初始化,因为我们的spa项目中,用户退出登录需要断开socket连接,用户登录后又需要重新连接,所以重新初始化承接的是切换用户重连的功能。事件订阅是由于socket传递消息全靠原生的onmes...
any类型在ts中我们只有有很多类型,比如:string、number、boolean等等,那么any这个类型怎么去理解呢?我们可以将其看做是一个超级类型集合,下面举个例子:type A = string; type B = number; type C = string | number; type D = string | number | boolean;可以看到,C和D里面都包含了string和number,那么他们都可以包含类型A和类型B,而any类型则是一个包含都有类型的一个集合。因为包含了所有,所以它可以很自由的去使用,从某种角度来看,any就是告诉ts,不需要来检测我...
前言最开始的时候写ts的时候遇到过这种问题,为什么String类型不能赋值给string类型,他们不都是字符串吗?在js中不是万物皆对象吗?同类型为什么不可以?const a: string = "a"; const b: String = a; const c: string = b;可以看到string类型可以赋值给String,而String类型不能赋值给string。解惑在JavaScript中,String、Number这种被称为包装器,你可以理解为他是一个类或者是构造函数,它返回的是一个对象,而string是一个字面量,被称为原始数据类型。原始数据类型(P...
前言pinia的作者最近在博客上放出了一篇pinia的使用文章:《My Top 5 Tips for using Pinia》,里面讲述了5个一般不怎么知道的使用技巧,但是由于讲的很浅,我这边自己理解了一下,做了一些解释,顺带记个笔记。不要创建无用的 getter这点我感同身受,在最初学习vuex的时候,前辈们总是会说,getter有缓存,性能会更好,于是,在大多数的教程中,我们总是能看到这种示例写法:export default Vuex.Store({ state: () => ({ counter: 0 }), getters: { ...
前言本来debian在安装的时候就可以选择国内的源,本来我以为这样就行了,不用自己在手动换,结果今天在使用更新命令时就给我卡住了,开始请求官方源了。难崩,还得自己换源解决问题。教程我们需要打开源文件:/etc/apt/sources.list ,你可以使用nano编辑或者ssh软件自带的文件管理功能修改文件。将里面deb和dep-src全部注释,注意这个注释是在每行前面加#号,大概如下:# deb http://mirrors.ustc.edu.cn/debian/ bookworm main non-free-firmware # deb-src http://mirrors.ustc...
前言最近新学到一招,利用原生css实现首屏骨架,这样即可以省去在Home.vue组件中单独创建骨架,而且对html结构是0添加。先看看预览图:效果还是可以的。教程原理就是利用background-image的多重渐变实现骨架占位,配合background-size和background-position进行精准定位,如果你的骨架是大量重复内容,还可以配置background-repeat: repeat-y;进行y轴重复渲染,效果更佳。然后通过动画控制整体的透明度变化实现动效。再通过:empty伪类实现对#app是否渲染的判断。:empty会在对应的元素内部没有任何内容时生效。不多说,直...
前言多页面其实可以理解为多个独立的业务之间共享部分代码逻辑的实现。业务之间是相对独立的,只是小部分或者大部分的代码是可以共用的,常见的一个场景就是:改头换面形式的换肤。不同的皮肤之间毫无可复用组件代码的情况下,我们只能将通用的业务逻辑抽离成可复用的部分,简单点来说就是将数据与ui分离,数据是共用部分,ui是各自独立。最终衍生出的多页面结构大体如下:pages ├── pageA │ ├── App.vue │ ├── index.html │ ├── main.ts └── pageB ├── App.vue ├── index.html └── ma...
inherit 继承关键字这是一个从IE8就开始支持的关键词,用于继承上层的样式效果,比如字体大小,字体颜色等,也是用的比较多的一个关键词,这里就不多说。initial 初始值关键词initial可以把css的属性还原成css语法中规定的初始值,但是需要注意的是这里的初始的值不是元素默认的值,而是css语法规范中定义的初始值。p { display: initial; }p元素默认是block盒子,但是当我们使用initial时你会发现它变成了一个inline盒子了,所以不要搞混了这个关键词的作用。unset 不固定值关键词如果当前使用的css属性是具有继承特性的,unset就等同于...
最近评论