《Nest 通关秘籍》学习nest笔记 Provide注入、循环依赖、动态Module

灵活的Provide注入 在 Module 的 providers 里声明: 其实这是一种简写,完整的写法是这样的: 通过 provide 指定注入的 token,通过 useClass 指定注入的对象的类,Nest 会自动对它做实例化再注入。 如果不想用构造器注入,也可以属性注入: 通过 @Inject 指定注入的 provider 的 token 即可。 当然,这个 token 也可以是字符串: 如果 token 是字符串的话,注入的时候就要用 @Inject 手动指定注入对象的 token 了: 调试一下,确实也注入了的。 Module、Service循环依赖怎么办 其实我们可以先单独创建这两个 Module,然后再让两者关联起来。 也就是用 forwardRef 的方式: 动态Module 有的时候我们希望 import 的时候给这个模块传一些参数,动态生成模块的内容,怎么办呢? 这时候就需要 Dynamic Module 了: import { DynamicModule, Read more…

一个小小的邮件模板搜索排序,前端交互相互拉扯,有这么难吗?

最近来了个需求:给现有邮件模板增加搜索功能。但是仅仅是一个如此小的需求,因为新来的交互决定对现有前端功能进行摧毁式大改 ,其预期效果版本竟然是现有交互改版之前的那个版本。。。 这一开倒车的行为招到我的强烈反对,跟交互多次拉锯战后,最终同意听我的在现有结构上进行新增改动。 没错,就是这么硬气,因为她给的理由无法说服改回老版本。 需求 效果大致如下 如果搜索关键词既命中模板名称,又命中了模板目录,则模板名称排在前面。 需求分析 因为现有的模板信息接口已经全部返回,所以本功能全部由前端完成,前端在全量数据里面进行搜索,排序及展示。 接口返回的数据结构类似 [{ name: "目录1", code: 'a001', type: 'CATEGORY', children: [{ name: "目录2", code: 'a002', type: 'CATEGORY', children: [{ name: "目录22", code: 'a0022', type: 'CATEGORY', }, { name: "模板21", code: 'm001', type: 'TEMPLATE', }]}, { name: "模板1", code: 'm001', type: 'TEMPLATE', } Read more…

使用app的华为应用内支付服务还是小心为上,2023年了还有人在支付场景使用http。。。

近期查看邮件的时候发现华为开发者联盟发的一封邮件,大致意思就是出于安全考虑,将于2023年10月1日全面限制应用内支付服务使用HTTP回调地址了。 众所周知HTTP协议以明文方式发送内容,不提供任何方式的数据加密。因此它不适合传输一些敏感信息,典型的支付场景就属于敏感信息。 https则是具有安全性的ssl加密传输协议。http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。并且https协议需要到ca申请证书。 HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。 现在很多网站都是用https了,即使不涉及敏感信息,也在用https了。根据邮件看来,目前还存在少量的开发者以及其所属公司还在使用http,并且还是在支付场景。。。这类公司一般都是一些小厂,或者一些小众app,或者是别有企图的公司在恶意使用吧。 大家还是小心为上,既然在华为应用中存在此类情况,小米、OV等,也极可能有类似的情况,大家自己小心为上,尽量或者不要在一些非知名app内进行支付。 信函具体内容如下: 尊敬的开发者,您好! 为共建良好的网络生态环境,给用户提供更加安全可靠的使用体验,应用内支付服务将限制使用不安全的HTTP回调地址,以满足安全需要。 出于安全考虑,将于2023年10月1日全面限制HTTP类型回调地址的使用。 如您的应用在使用应用内支付服务时使用了HTTP类型的回调地址,请您及时切换到HTTPS类型的回调地址,避免因HTTP回调地址被限制影响您无法正常收到支付结果回调通知。 如下两处的回调地址将受影响: 1、pay 、productPay接口请求参数中的url字段值是否为http:// 开头,若是则需要修改为HTTPS类型。 2、检查开发者联盟上的回调地址配置。 步骤1:用华为开发者帐号登录“华为开发者联盟”,点击右上角“管理中心”,进入管理中心。 步骤2:点击页面左侧“应用服务”,进入“开发服务”下的“支付”页面。 步骤3:检查各个产品的回调地址配置是否为http:// 开头,若是则需要修改为HTTPS类型。 如有疑问可通过在线提单方式咨询,感谢您的支持! 华为开发者联盟 2023年5月26日 信函内容截图如下:

浏览器web-push时提示Push notification prompting can only be done from a user gesture最佳实践

在实现浏览器的web-push时,在某些浏览器上可能会收到“Push notification prompting can only be done from a user gesture”。 让我们看看为什么有些浏览器强制执行此规则,如果不遵守会怎样呢?应该如何让我们的通知方案适用于所有浏览器呢? 问题分析 我们为了从网站向用户发送通知,是需要请求用户许可的。 正如许多网站所做的那样,我们可能认为最好的解决方案是让用户在进入网站后立即订阅通知。 但是这其实并不友好,设置会让用户很反感,也正是出于这个原因,如果网站在页面加载时开始请求消息通知的用户许可,一些浏览器已经决定阻止权限提示。 所以我们需要等待用户单击按钮或类似的东西,然后才显示请求权限提示(因为这是在用户生成的事件中)。 如果不遵守这个规则,浏览器只会返回错误,不会显示提示。 Safari上收到此错误: Push notification prompting can only be done from a user gesture. Firefox上得到这个错误: The Notification permission may only be requested from inside a short running user-generated event handler. 因为目前Chrome允许您在页面加载时显示权限提示,因此您不会在 Chrome 上收到任何错误。而我们绝大多数都是在chrome进行调试开发的,所以自己的方案可能有问题,但是发现不了。 最佳实践 Read more…

文本划词标注功能代码实现

背景 产品需求是要支持能将一段文本选取片段并打上对应的tag,并且支持回显,同一个片段只能打一个tag(或者叫标注),tag之间不能嵌套,这算是NLP项目中一个常见功能了。 给不清楚的小伙伴简单介绍下 就是将上面的用户语料文本“我要取消订单,因为生病了,我能提供医院证明”中的部分文本打tag,比如将“**生病*”打上“取消原因**”的tag 最后效果如下图所示 技术实现 方案一 在功能开发初期,因为没有回显需求,当时采取了类似关键词高亮的做法来作为技术实现雏形了。 代码片段 if (range.commonAncestorContainer.nodeType === 3) { const childNodes = parent.childNodes; childNodes.forEach(item => { if (item=== range.commonAncestorContainer){ const fragment = document.createElement('span'); fragment.className = 'fragment'; fragment.innerHTML = escapeHtml(item.data).replace( new RegExp(keyword, 'g'), `<span class="_test"> <span class="annotation_container"> <span class="annotation_target">${keyword}</span> </span> </span>`, ); item.replaceWith(fragment); } } ) Read more…

React函数函数式组件的防抖失效和闭包陷阱只会二选一?

项目中输入搜索联想的场景我们通常会加入防抖,减少对服务端造成的压力,在React的函数式组件中使用的时候一不小心就掉进坑里了。 我们的防抖函数实现如下 function debounce(handler, wait) { let timeId = null; return function(…rest) { timeId && clearTimeout(timeId); timeId = setTimeout(function () { handler.apply(this, rest) }, wait); } } 代码1 import React, { useState } from 'react'; import ReactDOM from 'react-dom'; import { Input } from 'antd'; function debounce(handler, wait) { let Read more…

微前端qiankun问题You need to export the functional lifecycles in xxx entry终极解决方案

背景 最近开启了自己Q2的OKR项目,将手上的后台系统,改成微前端模式,方便后续的维护。 目前这个后台系统(知识库管理后台)的部分页面也作为微前端微应用的一部分,嵌入另一个微前端的主应用(综合管理后台)里面的,也就是说它既作为微前端的微应用,也作为了微应用的主应用。 遇到问题 在调试过程中,我尝试将该项目在本地改造成主应用在本地跑起来,同时注册的微应用是它目前的线上版本,但是在实际调试过程中还是遇到了Application died in status LOADING_SOURCE_CODE: You need to export the functional lifecycles in xxx entry。 写本文章时测试发现没问题了。。。上班继续测试下。 Application died in status LOADING_SOURCE_CODE: You need to export the functional lifecycles in xxx entry,我相信这个报错几乎所有接入微前端的同学都碰到过的。 解决过程 这个官网也给了很明确的解决方案。 官网FAQ 原理探索 我觉得应该重点关注图中我划线的1、2、5三点了。 概括来说主要有几点: 看入口文件(也就是React或Vue项目的render根节点的那个文件)是否配置了bootstrap,mount等生命周期函数,及时里面的内容是空的,仅一行console也行,但是必须要有。 让qiankun打包后的哪个js文件是上述你暴露了生命周期的入口文件 因为qiankun一般是通过解析html的源代码中解析js,并试图读取哪个是entry。html中引入大于一个js的,就要格外注意entry的配置,方便主应用识别到。 上图就是知识库管理后台线上项目的html,可以看到上面引入了三个js,index.xx.js是项目入口,在html中标记了entry向主应用来表明它是entry文件。 作为上述综合管理后台的子应用时,一切正常,但是我在本地调试还是出问题了,Application died in status LOADING_SOURCE_CODE: Read more…

让hexo的分类列表支持子分类导航(优化版)

之前写过hexo的分类列表支持子分类导航,简单回顾下需求,就是想让列表页能够根据不同的年份来切换,效果如下: review 当时采用的临时方案,虽然效果是达到了,但是具体实现不够优雅,里面还有hardcode,代码如下 let categoryParent=''; page.posts.sort('date', -1).each(function(post){ if(post._categoryParent) { categoryParent = post._categoryParent; } }) let yearList=['2021', '2020', '2019']; 每篇文章还需要配置_categoryParent,就是为了在category.ejs里面读取,其实url上面就有这部分信息 yearList是直接在编码中写死的,这个才是需要配置的 refactor 在尝试从location获取_categoryParent时报错了,提示location未定义,在hexo官网看文档发现可以在page.path或者全局变量url里面获取。 let pathList = page.path.split('/'); let categoryIndex = pathList.indexOf(page.category) let categoryParent = pathList[categoryIndex – 1]; 根据/分割,在年份信息前面那个就是categoryParent信息啦。 在配置表里面配置年份信息 比如这样配置 用形如_xxYearList的配置项。 # training展示年份列表 _trainingYearList: 2021,2020,2019 我们可以这样读取 let conf = theme['_' + Read more…

让hexo的分类列表支持子分类导航

需求 之前我们的分类列表是这样的 里面有三篇文章,三个年份个一张,即2021、2020、2019 现在需要支持在列表页根据不同的年份来切换,效果如下图: 前置知识 这就涉及到对hexo的category的了解了。 假设我们有个文章A是这样设置分类信息的 categories: – [training, 2021] – [y2021] 同时有个文章B是这样设置分类信息的 categories: – [training] 测试发现如下现象: 我们访问/categories/training,该列表会展示A、B两篇文章 我们访问/categories/training/2021,该列表会展示A这一篇文章 我们访问/categories/2021,会提示找不到对应的文章 我们访问/categories/y2021,该列表会展示A这一篇文章 可以发现 categories中同一个[]里面的分类之间是父子级关系 categories中不同[]里面的分类是并列关系 同时在编写模板的时候发现hexo认为每一个特定的分类列表只隶属于某一个category,也就是category.ejs中page.category只会是一个值,所以上述现象对应的page.category分别是: 现象1中的category为training 现象2中的category为2021,并非[training, 2021] 现象3中的category为2021 现象4中的category为y2021 实战 需求其实加入这样的子分类“导航器”(姑且这么称呼吧),这里只不过是按年份来做子分类。 然后每个对应的url是/categories/training/2021、/categories/training/2020,每个url都含有这个“导航器” 具体就需要修改/layout/_pages/category.ejs文件中下面的部分了,在里面加入实现“导航器”的代码即可。 <div class="post-stream-container"> <% page.posts.sort('date', -1).each(function(post){ %> <div class="grid-item"> <%- partial('_partial/post-entry', { post: post, index: true, Read more…

android运行时授权读取短信后仍收不到短信

最近想给自己做一个短息转发的功能,这就需要读取短信的权限了,这里就用到了 代码里面这样写到 AndroidManifest.xml文件 <receiver android:name=".service.SmsReceiver" android:exported="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver> SmsReceiver文件 class SmsReceiver : BroadcastReceiver() { init { Log.v("dimos", "SmsReceiver create") } override fun onReceive(context: Context, intent: Intent) { val body: String = SmsHelper.getSmsBody(intent) val address: String = SmsHelper.getSmsAddress(intent) Log.v("sms received", "$address,$body") showSms(context, "短信源自$address", body) Read more…