nest 学习3

学习小册(nest通关秘籍)

邮箱验证码登陆

流程图:

在这里插入图片描述
邮箱作为key,生成随机验证码,然后放到redis中。调用邮箱api发送邮箱。

前端获取到code后,将验证码输入传给后端,后端根据邮箱取出redis数据,比对验证码,通过则去mysql查用户数据,生成jwt token返回。

定时任务+Redis实现阅读量计数
  • 1 在redis中存储user和article的关系,比如user_test_article_nest_sturdy,10分钟后删除。期间,如果判断存在这个key,则说明该用户看过这篇文章,不更新阅读量,否则才更新。
  • 10分钟后,这个人在看文章,就算一次新的阅读量。
  • 访问文章的时候,把阅读量写到redis中,不更新数据库,等业务低峰期再把最新的阅读量写入数据库,比如凌晨4点写入数据库。sql压力就不大。
定时任务表达式

在这里插入图片描述
比如

7 12 13 10 * ?
每个月的10号的13:12:07执行,然后星期需要用?,因为不知道具体星期几,用*会每天都执行。

事件通信

两个不相关的业务模块,需要互相调用的时候,注入对应的模块是不合理的,这时候可以用到event emitter(事件总线)通信,达到解耦的目的。

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { EventEmitterModule } from '@nestjs/event-emitter';

@Module({
  imports: [
    EventEmitterModule.forRoot(),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

触发,
在这里插入图片描述
监听

@OnEvent('aaa.find')
handleAaaFind(data) {
    console.log('aaa find 调用', data)
    this.create(new CreateBbbDto());
}

当调用findAll的时候,就会触发aaa.find事件,这时候handleAaaFind就会被执行。

pinyin+和风天气api实现天气查询

和风天气提供api调用查询天气。
步骤,先查询地方的id,再通过id查询天气。

https://geoapi.qweather.com/v2/city/lookup?location=qingdao&key=注册和风项目的key//获取通过地方中文名地方id
https://api.qweather.com/v7/weather/7d?location=101120201&key=注册和风项目的key //通过地方id获取天气信息。

pinyin这个包可以拿到中文的拼音。

让用户直接选择城市,网上也有很多json数据,可以直接拿到城市对应的id。

记录请求id

通过header里的X-Forwarded-For可以拿到请求浏览器的ip地址,通过ip可以获取对应地区信息。

短链服务

长链接分享不方便,可以用短链服务。
用递增id,记录对应每个url,再把映射关系存到数据库。
用户访问短链的时候,从数据库中取出链接,返回302/301重定向。
302是临时重定向,301是永久重定向。
301对短链服务的压力较小,但302可以记录链接的点击次数,做分析,一般都是用302来重定向。

一般每个url的id会使用base64/62编码实现。
base64就是26个大/小写字母,10个数字,两个特殊字符,一共64
base62则是去掉了两个特殊字符,一共62.

压缩码

创建一张存放映射关系的表,用mysql的自增id进行base62后,最为压缩吗,访问短链的时候,根据压缩码查询这个表,拿到长链接。

这样有个问题,用自增id做压缩吗,别人容易拿到上一个/下一个压缩码,会有安全问题。

用crypto加盐呢?

const crypto = require('crypto');

function md5(str) {
  const hash = crypto.createHash('md5');
  hash.update(str);
  return hash.digest('hex');
}

console.log(md5('111222'))

比较长,有32位。

用随机数的方式生产压缩码。

const base62 = require("base62/lib/ascii");

function generateRandomStr(len) {
    let str = '';
    for(let i = 0; i < len; i++) {
        const num = Math.floor(Math.random() * 62);
        str += base62.encode(num);
    }
    return str;
}

console.log(generateRandomStr(6));

随机生成0-61的数字,转成字符。但是随机数也有碰撞的可能,可以在查表的时候检查下是否有重复,有的话重新生成,这样会有性能问题。

可以提前生成一批压缩码,存到数据库里面,用的时候直接取,定时任务每天4点生成一批。

小结:

  • 自增id作为压缩码,保证唯一但不安全。
  • url加盐后取一部分,有碰撞可能,不唯一
  • 随机生成再检测重复,保证唯一且不连续,但是有性能问题,用提前批量生产方式可以解决。
推送数据

websocket双向数据通信。
在这里插入图片描述
通过http切换协议,然后进行websocket各级数据的通信。

Http: Server Sent Event
在这里插入图片描述
服务端返回的Content-Type是text/event-stream,这是一个流,可以多次返回内容。
Server Sent Event就是通过这种消息来随时推送数据的。

比如CICD平台的构建日志,通义千问回答的问题。
在这里插入图片描述
nest实现Sse

@Sse('stream')
stream() {
    return new Observable((observer) => {
      observer.next({ data: { msg: 'aaa'} });

      setTimeout(() => {
        observer.next({ data: { msg: 'bbb'} });
      }, 2000);

      setTimeout(() => {
        observer.next({ data: { msg: 'ccc'} });
      }, 5000);
    });
}

前端请求

import { useEffect } from 'react';

function App() {

  useEffect(() => {
    const eventSource = new EventSource('http://localhost:3000/stream');
    eventSource.onmessage = ({ data }) => {
      console.log('New message', JSON.parse(data));
    };
  }, []);

  return (
    <div>hello</div>
  );
}

export default App;

EventSource是浏览器原生api,用来获取sse接口的响应。

SSE连接断了后,会通过浏览器自动重连,websocket断了后需要手动重连。

日志实时推送:
tail -f xx.log 可以看到xx.log的最新内容。
通过child_proces模块的exec执行这个命令,可以监听他的stdout输出。

const { exec } = require("child_process");

const childProcess = exec('tail -f ./log');

childProcess.stdout.on('data', (msg) => {
    console.log(msg);
});

然后添加一个sse接口

@Sse('stream2')
stream2() {
const childProcess = exec('tail -f ./log');

return new Observable((observer) => {
  childProcess.stdout.on('data', (msg) => {
    observer.next({ data: { msg: msg.toString() }});
  })
});

将childProcess的输出实时返回给前端。

这样当我们修改log文件的时候,就可以实时响应在浏览器。

minio搭建自己的oss服务

文件上传一般用oss(Object storage Service)对象存储服务来存文件,支持分布式扩展,不用担心容量问题,比如阿里的oss。如果要死有的oss服务,可以用minio来做。
用docker拉minio镜像,创建一个容器运行minio,然后可以在node里面用他的sdk做上传和下载操作,跟阿里的sso操作类似。因为sso一般都实现了亚马逊(AWS Simple Storage Serivce)S3的规范。

在这里插入图片描述
前端如何直传给oss服务,再将地址给服务器在这里插入图片描述
阿里云oss可以通过临时凭证的方式直穿oss,也就是应用服务器返回一个临时凭证,前端用这个临时凭证上传oss,不需要把sccessKey暴露给前端。

基于sharp实现图片压缩。

sharp这个包可以处理各种图片,调整大小,旋转,压缩,适用于上传一些网站的限制。

大文件流式下载

正常我们下载文件

@Get('download')
@Header('Content-Disposition', `attachment; filename="test.json"`)
download(@Res() res: Response) {
    const content = fs.readFileSync('package.json');

    res.end(content);
}

只要设置了响应头,就会触发浏览器对应的下载操作,但这样是文件全部读出后才返回,文件太大就会占内存。
可以读出一部分返回一部分。http支持这个功能。transfer-encoding:chunked

从服务器下载一个文件的时候,如何知道文件下载完了呢?

  • 1 header带上Content-Length,浏览器下载到这个长度就结束。
  • 2设置 transfer-encoding:chunked,他是不固定长度的,服务器不断返回内容,直接返回一个空的内容代表结束,这样不管内容多少都可以分块返回,而不用指定Content-Length;
@Get('download2')
@Header('Content-Disposition', `attachment; filename="test.json"`)
download2(@Res() res: Response) {
    const stream = fs.createReadStream('package.json');

    stream.pipe(res);
}

@Get('download3')
download3() {
    const stream = fs.createReadStream('package.json');

    return new StreamableFile(stream, {
      type: 'text/plain',
      disposition: `attachment; filename="test.json"`
    });
}

node的stream是分块读取内容的,配合流失返回数据很合适。
默认会设置响应头的Transfer-Encoding为chunked

这里可以使用nest封装的StreamableFile来实现,避免自己处理data error事件等。

大文件上传用分片上传,大文件下载用分片下载。

扫二维码登陆

二维码识别出来就是一个url,比如常用的登陆二维码。在浏览器打开就是下载app,在app打开就是登陆确认界面。
二维码一共有5个状态:

  • 未扫描
  • 已扫瞄,等待确认
  • 已扫瞄,用户同意授权。
  • 已扫瞄,用户取消授权。
  • 已过期

二维码的状态一般用轮询来做。
未扫描前,可能返回status为0,然后一秒轮询,扫描后可能返回status为1,此时手机点击确认登陆或者取消后,会发请求修改id对应的二维码状态,pc端通过轮询也能实时修改状态。

流程是
在这里插入图片描述

  • 服务端有个generator接口,负责生成随机二维码id,存到redis,并返回二维码。
  • 有个check接口,返回redis的二维码状态。
  • 手机app扫码后,没登陆,回调到登陆页面,登陆之后会进入登陆确认页面。
  • 从二维码中得到的url包括id,调用scan/cacnl/confirm接口修改二维码不同状态。
  • 如果用户登录后,我们这里采用jwt,会携带token,服务端可以从token取出用户信息,修改redis状态,并且将用户信息存入redis。
  • 另一边check接口判断状态是确认后,取出用户信息,生成jwt返回给pc端,这样就实现了登陆,
nest excel导入导出

前端使用xlsx这个包解析处理 excel文件,node里用exceljs这个包来处理


async function main(){
    const workbook = new Workbook();

    const workbook2 = await workbook.xlsx.readFile('./data.xlsx');

    workbook2.eachSheet((sheet, index1) => {
        console.log('工作表' + index1);

        sheet.eachRow((row, index2) => {
            const rowData = [];
    
            row.eachCell((cell, index3) => {
                rowData.push(cell.value);
            });

            console.log('行' + index2, rowData);
        })
    })
}

main();

在这里插入图片描述

excel支持最下面展示多个工作表。eachSheet就是遍历工作表的
层级关系:workbook(工作簿) > workSheet(工作表) > row(行) > cell(列)
如上,每一层都可以遍历,eachSheeteachRow eachCell,遍历工作表,遍历行,每一行还可以遍历列。
导出:

const { Workbook } = require('exceljs');

async function main(){
    const workbook = new Workbook();

    const worksheet = workbook.addWorksheet('guang111');

    worksheet.columns = [
        { header: 'ID', key: 'id', width: 20 },
        { header: '姓名', key: 'name', width: 30 },
        { header: '出生日期', key: 'birthday', width: 30},
        { header: '手机号', key: 'phone', width: 50 }
    ];

    const data = [
        { id: 1, name: '光光', birthday: new Date('1994-07-07'), phone: '13255555555' },
        { id: 2, name: '东东', birthday: new Date('1994-04-14'), phone: '13222222222' },
        { id: 3, name: '小刚', birthday: new Date('1995-08-08'), phone: '13211111111' }
    ]
    worksheet.addRows(data);

    workbook.xlsx.writeFile('./data2.xlsx');    
}

main();

先addWroksheet,设置columns后,再addRows,还可以设置格式,字体,背景色等等。

代码动态生成ppt

demo: 整理一份中国所有大学的ppt

用 puppeteer 来爬取大学的校徽、名字、介绍,然后用这些信息来生成 pdf 等。
用SSE(server sent event)的方式创建接口,不断返回爬取到的信息,用pptxgenjs来生成ppt。

获取服务器的cpu, 内存,磁盘, ip等信息。

通过 node 的 os 模块的 api 以及 node-disk-info 这个包。
如获取cpu占用情况。

@Get('status')
status() {
    const cpus = os.cpus();
    const cpuInfo = cpus.reduce(
      (info, cpu) => {
        info.cpuNum += 1;
        info.user += cpu.times.user;
        info.sys += cpu.times.sys;
        info.idle += cpu.times.idle;
        info.total += cpu.times.user + cpu.times.sys + cpu.times.idle;
        return info;
      },
      { user: 0, sys: 0, idle: 0, total: 0, cpuNum: 0 },
    );
    const cpu = {
      cpuNum: cpuInfo.cpuNum,
      sys: ((cpuInfo.sys / cpuInfo.total) * 100).toFixed(2),
      used: ((cpuInfo.user / cpuInfo.total) * 100).toFixed(2),
      free: ((cpuInfo.idle / cpuInfo.total) * 100).toFixed(2),
    };
    return cpu;
}
Nest实现国际化

nestjs-i18n

import { I18nModule, QueryResolver } from 'nestjs-i18n';
import * as path from 'path';

@Module({
  imports: [
    I18nModule.forRoot({
      fallbackLanguage: 'en',
      loaderOptions: {
        path: path.join(__dirname, '/i18n/'), //语言的资源包
        watch: true,
      },
      resolvers: [
        new QueryResolver(["lang", "l"]), //query中获取信息 ?lang=en
        new HeaderResolver(["x-custom-lang"]), //header中获取
        new CookieResolver(['lang']), //cookie中获取
        AcceptLanguageResolver,
      ]
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

使用

import { Inject, Injectable } from '@nestjs/common';
import { I18nContext, I18nService } from 'nestjs-i18n';

@Injectable()
export class AppService {

  @Inject()
  i18n: I18nService;

  getHello(): string {
    return this.i18n.t('test.hello', { lang: I18nContext.current().lang })
  }
}

像验证body的一些class,不在ioc容器中,不能注入I18NSerivce,可以用nest-i18n提供的I18nValidationPipe来替换ValidationPipe。再把对应的报错改成资源的key
在这里插入图片描述
还有占位符,比如
test: 密码不能少于{num}位
test1: "你好世界,{name}"
使用的时候

@MinLength(6, {
    message: i18nValidationMessage("validate.test", {
        num: 88
    })
})

getHello(): string {
    return this.i18n.t('test.test1', {
      lang: I18nContext.current().lang,
      args: {
        name: 'test'
      }
    })
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/942294.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

原点安全再次入选信通院 2024 大数据“星河”案例

近日&#xff0c;中国信息通信研究院和中国通信标准化协会大数据技术标准推进委员会&#xff08;CCSA TC601&#xff09;共同组织开展的 2024 大数据“星河&#xff08;Galaxy&#xff09;”案例征集活动结果正式公布。由工银瑞信基金管理有限公司、北京原点数安科技有限公司联…

RabbitMQ 的7种工作模式

RabbitMQ 共提供了7种⼯作模式,进⾏消息传递,. 官⽅⽂档:RabbitMQ Tutorials | RabbitMQ 1.Simple(简单模式) P:⽣产者,也就是要发送消息的程序 C:消费者,消息的接收者 Queue:消息队列,图中⻩⾊背景部分.类似⼀个邮箱,可以缓存消息;⽣产者向其中投递消息,消费者从其中取出消息…

Restaurants WebAPI(四)——Identity

文章目录 项目地址一、Authentication&#xff08;身份认证&#xff09;1.1 配置环境(解决类库包无法引用)1.2 使用Authentication控制Controller的访问1.3 获取User的Context1.3.1 在Application下创建User文件夹1. 创建User.cs record类封装角色信息2. 创建UserContext.cs提供…

010 Qt_输入类控件(LineEdit、TextEdit、ComboBox、SpinBox、DateTimeEdit、Dial、Slider)

文章目录 前言一、QLineEdit1.简介2.常见属性及说明3.重要信号及说明4.示例一&#xff1a;用户登录界面5.示例二&#xff1a;验证两次输入的密码是否一致显示密码 二、TextEdit1.简介2.常见属性及说明3.重要信号及说明4.示例一&#xff1a;获取多行输入框的内容5.示例二&#x…

Vue3:uv-upload图片上传

效果图&#xff1a; 参考文档&#xff1a; Upload 上传 | 我的资料管理-uv-ui 是全面兼容vue32、nvue、app、h5、小程序等多端的uni-app生态框架 (uvui.cn) 代码&#xff1a; <view class"greenBtn_zw2" click"handleAddGroup">添加班级群</vie…

通过Docker Compose来实现项目可以指定读取不同环境的yml包

通过Docker Compose来实现项目可以指定读取不同环境的yml包 1. 配置文件2. 启动命令 切换不同环境注意挂载的文件权限要777 1. 配置文件 version: 3.8 services:docker-test:image: openjdk:8-jdk-alpineports:- "${APP_PORT}:${CONTAINER_PORT}"volumes:- "${J…

华为实训课笔记 2024 1223-1224

华为实训 12/2312/24 12/23 [Huawei]stp enable --开启STP display stp brief --查询STP MSTID Port Role STP State Protection 实例ID 端口 端口角色 端口状态 是否开启保护[Huawei]display stp vlan xxxx --查询制定vlan的生成树计算结…

GitCode 光引计划投稿 | GoIoT:开源分布式物联网开发平台

GoIoT 是基于Gin 的开源分布式物联网&#xff08;IoT&#xff09;开发平台&#xff0c;用于快速开发&#xff0c;部署物联设备接入项目&#xff0c;是一套涵盖数据生产、数据使用和数据展示的解决方案。 GoIoT 开发平台&#xff0c;它是一个企业级物联网平台解决方案&#xff…

EasyGBS国标GB28181公网平台P2P远程访问故障诊断:云端服务端排查指南

随着信息技术的飞速发展&#xff0c;视频监控领域正经历从传统安防向智能化、网络化安防的深刻转变。EasyGBS平台&#xff0c;作为基于国标GB28181协议的视频流媒体平台&#xff0c;为用户提供了强大的视频监控直播功能。然而&#xff0c;在实际应用中&#xff0c;P2P远程访问可…

Vnlhun靶场Log4j2漏洞

相关概念 log4j2是Apache的⼀个java日志框架&#xff0c;我们借助它进行日志相关操作管理&#xff0c;然而在2021年末log4j2爆出了远程代码执行漏洞&#xff0c;属于严重等级的漏洞 漏洞原理 简单说就是当你使⽤log4j2中提供的⽅法去输出⽇志信息时&#xff0c;⽐如说最常⻅…

千兆网中的gmii与rgmii

物理链路上是千兆网。1 Gbps1000 Mb/s1000/8 MB/s125 MB/s&#xff0c;这是和你的测试设备相连的1 Gbps物理带宽下的极速。关键点是1 B&#xff08;byte&#xff09;8 b&#xff08;bit&#xff09;。实际下载速度还取决于下载源的限制、出口的物理链路和运营商的限制。

2024-12-24 NO1. XR Interaction ToolKit 环境配置

文章目录 1 软件配置2 安装 XRToolKit3 配置 OpenXR4 安装示例场景5 运行测试 1 软件配置 Unity 版本&#xff1a;Unity6000.0.26 ​ 2 安装 XRToolKit 创建新项目&#xff08;URP 3D&#xff09;&#xff0c;点击进入 Asset Store。 进入“Unity Registry”页签&#xff0…

重温设计模式--外观模式

文章目录 外观模式&#xff08;Facade Pattern&#xff09;概述定义 外观模式UML图作用 外观模式的结构C 代码示例1C代码示例2总结 外观模式&#xff08;Facade Pattern&#xff09;概述 定义 外观模式是一种结构型设计模式&#xff0c;它为子系统中的一组接口提供了一个统一…

【恶意软件检测】一种基于API语义提取的Android恶意软件检测方法(期刊等级:CCF-B、Q2)

一种基于API语义提取的Android恶意软件检测方法 A novel Android malware detection method with API semantics extraction 摘要 由于Android框架和恶意软件的持续演变&#xff0c;使用过时应用程序训练的传统恶意软件检测方法在有效识别复杂演化的恶意软件方面已显不足。为…

【微信小程序】2|轮播图 | 我的咖啡店-综合实训

轮播图 引言 在微信小程序中&#xff0c;轮播图是一种常见的用户界面元素&#xff0c;用于展示广告、产品图片等。本文将通过“我的咖啡店”小程序的轮播图实现&#xff0c;详细介绍如何在微信小程序中创建和管理轮播图。 轮播图数据准备 首先&#xff0c;在home.js文件中&a…

RT-DETR学习笔记(2)

七、IOU-aware query selection 下图是原始DETR。content query 是初始化为0的label embedding, position query 是通过nn.Embedding初始化的一个嵌入矩阵&#xff0c;这两部分没有任何的先验信息&#xff0c;导致DETR的收敛慢。 RT-DETR则提出要给这两部分&#xff08;conten…

fpgafor循环语句使用

genvar i;//循环变量名称 generate for(i0;i<4;ii1)begin:tx//自己定义名称 //循环内容 end endgenerate12位的16进制乘以4就是48位位宽的2进制 因为 222*2(2^4)16

62.基于SpringBoot + Vue实现的前后端分离-驾校预约学习系统(项目+论文)

项目介绍 伴随着信息技术与互联网技术的不断发展&#xff0c;人们进到了一个新的信息化时代&#xff0c;传统管理技术性没法高效率、容易地管理信息内容。为了实现时代的发展必须&#xff0c;提升管理高效率&#xff0c;各种各样管理管理体系应时而生&#xff0c;各个领域陆续进…

网站灰度发布?Tomcat的8005、8009、8080三个端口的作用什么是CDNLVS、Nginx和Haproxy的优缺点服务器无法开机时

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把…

路由器转发数据报的封装过程

✍作者&#xff1a;柒烨带你飞 &#x1f4aa;格言&#xff1a;生活的情况越艰难&#xff0c;我越感到自己更坚强&#xff1b;我这个人走得很慢&#xff0c;但我从不后退。 &#x1f4dc;系列专栏&#xff1a;网路安全入门系列 目录 路由器转发数据的封装过程 路由器转发数据的封…