Wednesday, August 18, 2021

V2EX - 技术

V2EX - 技术


如何突破信息茧房?

Posted: 18 Aug 2021 04:07 AM PDT

如果一个人,比如我,每天只刷 b 站,知乎,v2ex,youtube
那么跟只刷微博(不是鄙视微博,只是不喜欢看娱乐新闻)的人似乎没有本质区别,只是活在一个内容不一样的茧房,但是它仍然是个茧房,信息的来源完全不由你自己控制,被算法以及背后的人工支配

明智的选择是像一条蠕动的毛毛虫那样:自己造一个茧房
利用 rsshub 作为信息来源,收集全网的高效信息,搭配好用的 rss 阅读器,同时向 rsshub 贡献它没有的源
可以做到完全支配自己的信息世界

京东让我允许追踪 要不要脸啊

Posted: 18 Aug 2021 04:03 AM PDT

b29631e9c2fba2efe9188bba37ab232.png

TapTap 最近强制更新后不给存储权限无法安装游戏

Posted: 18 Aug 2021 04:02 AM PDT

很早之前 TapTap 就是要存储权限,但是不给的话也能去 Android/data/com.taptap 下面把安装包找出来

但是现在强更后的版本将安装包下载到了 /data/data/com.taptap 下

也就是说不 root 手机的情况下只能老老实实给存储权限

平台自己都如此做,对里面游戏的审核力度现在也保持怀疑了

CAS 认证服务有人用过吗?

Posted: 18 Aug 2021 04:01 AM PDT

按照官方文档和 README 去配置 cas web management,每个分支都试过去了,没有能正常使用的,总会遇到这样或那样的问题。

看 cas 的 github 还挺活跃,star 也很多,是我打开的方式不对吗?

vue3 里面父组件向子组件传值的一个问题

Posted: 18 Aug 2021 04:00 AM PDT

在 vue2 里面:

 // 父组件 <template>   <ComponentA v-bind.sync="obj" /> </template>   <script> data() {   return {     obj: {a: 1, b: 2}   } } </script>   // 然后在子组件 ComponentA 里面直接去拿 a 和 b 就好了,就相当于是 v-bind 把 obj 拆开了,添加了.sync 修饰符又能同步修改 props: ['a', 'b']  

如果按照 vue3 的写法:

// 父组件 <template>   <ComponentA v-model:obj="obj" v-model:c="c" /> </template>  <script setup lang="ts"> import { reactive, ref } from 'vue';  const obj = reactive({   a: 1,   b: 2 }); const c = ref(0) </script>  // 子组件  <script setup lang="ts"> const props = defineProps<{   obj: {     a: number;     b: number;   };   c: number; }>();  const emit = defineEmits(['update:obj', 'update:c']);  function syncEdit() {   emit('update:obj', { a: 2, b: 1 }); // 这个没有作用   emit('update:c', 2); // 这个起作用了 }  </script> 

现在遇到了两问题,求大佬们解答一下:

1.如何在 vue3 里面把 obj 拆开,并且实现类似于.sync 的效果

2.为什么 v-model:xxx="xxx",当 xxx 为 reactive 定义的时候不能同步修改,而 ref 可以

不用谢,金九银十 不准备, 十一十二 徒伤悲 ,高频面试题给你全划重点了,点赞收藏

Posted: 18 Aug 2021 03:55 AM PDT

持续更新的 Github

Vue 系列

Vue3 系列

ES6 系列

Javascript 系列

CSS 系列

webpack 系列

HTTP 系列

NodeJS 系列

React 系列

关于开发人员离职 服务器和数据库密码修改问题

Posted: 18 Aug 2021 03:41 AM PDT

服务器和数据密码都是写在代码的配置文件里的,开发人员离职需要重新修改一遍,比较麻烦,有没有比较好的解决方案不需要修改?

golang 有什么 TCP 框架?

Posted: 18 Aug 2021 03:35 AM PDT

可以管理连接, 心跳包 处理粘包等,
web 方面的很多, tcp 的没找到,大家做 TCP 都用什么呢?

吐槽一下高德地图导航,能不能走点心啊

Posted: 18 Aug 2021 03:30 AM PDT

  1. 早高峰,相同时间段,相同线路,预计时间严重不准。

高德预计:40 分钟,但实际 1 小时 20 分钟。 实际每天差不多,(下雨天时间更长), 但是高德地图还是显示 40 分钟。 结果,开出去表小时后,高德显示还要 40 分钟。

它就不能学习调整一下吗?

  1. 非高峰时间,车子开的快飞起,也没法在预计时间内到达。 是不是高德把红灯时间都默认绿灯了?

感觉高德预计时间少报一点,就能用户代认为你导航更智能些?


看样子我要试试其他导航, 看有没有导航这方面时间预测准的?

之前用过几次百度地图,但是语音听着不太习惯,也对百度这家公司不喜欢。

发现个 pure go 的 sqlite 驱动

Posted: 18 Aug 2021 03:21 AM PDT

源于 tg 群群友的推荐

文档: https://pkg.go.dev/modernc.org/sqlite 而且还有相应的 gorm 的驱动:https://github.com/cloudquery/sqlite

这样似乎用不到 cgo 了,而且 goreleaser 什么的好像都能跑

有没有人用过这个库,性能什么的差别大吗?如果不错的话感觉挺香的

su - root 用户出现 Segmentation fault

Posted: 18 Aug 2021 03:14 AM PDT

其他用户可以正常登陆,切换到 root 用户就不行,网上看了一大堆,还是不行 []$ su - Password: Last login: Wed Aug 18 16:33:48 CST 2021 on tty1 Last failed login: Wed Aug 18 16:34:01 CST 2021 on tty1 There was 1 failed login attempt since the last successful login. Segmentation fault

面对互联网公司对用户隐私的手越伸越长,我们能做些什么?

Posted: 18 Aug 2021 03:08 AM PDT

可以说不。

互联网公司强行索取或者偷偷收集用户隐私的行为越来越猖獗,无论是桌面端和移动端应用,还是新兴的车联网物联网等,都成为了获取用户隐私的途径。某些公司的隐私协议写得如同裹脚布一般又臭又长,甚至不同意就退出,用户事实上是被迫「同意」。

有时候并不是大家不在乎,而是大家没有选择。

在 V2EX 看到很多关于广告和隐私的讨论,受 996ICU 和 955WLB 等项目的影响,所以我想能不能也创建一个项目,用来记录滥用用户隐私的行为。

建立 Clean Apps ( https://github.com/0xHJK/CleanApps) 项目的初衷是列出尊重用户隐私的 App 和曝光过度收集隐私的 App,起到社区监督的作用,也帮助用户用脚投票,方便选择同类替代品。

适逢 App 整治力度加大,《数据安全法》即将实施,《个人信息保护法》已经三审。这样一个项目可以让更多人发声,可以让更多人看到。

让互联网为用户服务,而不是把用户变成互联网的产品。

初步计划:

  1. 记录 V2EX 近期讨论的滥用隐私问题
  2. 测试一些大厂的 App
  3. 对于违法违规行为举报至有关部门
  4. 讨论相关技术手段

项目地址: https://github.com/0xHJK/CleanApps

希望大家可以一起参与进来,再小的力量也是一种支持,感谢

怎么能用更舒服的方式看比较厚的实体书?

Posted: 18 Aug 2021 03:04 AM PDT

肯定不能手拿着看吧,肯定得放桌子上,但是放桌子上的时候,由于书比较厚,还得用手压着看,我看淘宝上有卖那种读书支架的,不知道怎么样。

如何检查 idea 卡顿的原因

Posted: 18 Aug 2021 03:02 AM PDT

频繁出现代码敲着敲着就卡住几秒 期间切换出来操作其他程序都正常 cpu 和内存占用都不高 有工具可以检查是什么导致的吗

92 年运维辞职创业给点建议

Posted: 18 Aug 2021 03:02 AM PDT

首先说说,目前的处于离职状态,有房贷一个月 4500 左右 离职原因:被上家单位压榨太严重想休息休息,还有一个原因是不想一辈子给别人打工看不到头,况且年龄越来越大就很害怕失业,所以想自己创业搞点项目!目前还没有特别好的项目,即便没有好的项目我也选择了先离职原因就是上家单位加班多熬夜多身体受不了!目前准备尝试的几个项目 1 、抖音电商 2 、抖音自媒体(美食方向) 为此特意注册了公司用于项目运作所需!但是现在有点迷茫不知道何去何从!有时候想不如继续找份工作上班算了,如果重新找份工作或许没有之前工作那么累,而且过的也算滋润吧,但是回头再想想一眼看不到头的打工生活我就够了!反正现在就是有点迷茫有点徘徊!

Gitea 上项目钩子失效

Posted: 18 Aug 2021 02:11 AM PDT

公司内网用的 gitea1.11+drone1.6 构建的 CI/CD 平台。

今天不知道为什么其中一个项目推送改动推送上去没有触发部署。项目-》管理 Web 钩子里面的推送记录是 500,报错{"message":"client is not authorized"}。网上也没找到相关的解决方案,有没有了解的大佬指点下。

[img]https://i.imgur.com/RABsLaS.png[/img]

[img]https://i.imgur.com/CdUXEdS.png[/img]

502 错误

Posted: 18 Aug 2021 01:56 AM PDT

2021/08/18 16:07:58 [error] 8967#0: *52 connect() failed (111: Connection refused) while connecting to upstream, client: 0000 server: 000000, request: "GET /favicon.ico HTTP/1.1", upstream: "http://000000:5701/favicon.ico", host: "0000000000", referrer: "http://*0000"

大佬们,请问这是什么问题啊,该怎么解决,谢谢

MySql 跨库操作出现奇怪问题

Posted: 18 Aug 2021 12:54 AM PDT

SELECT * FROM db1.table1 WHERE db1.table1.id = db2.table2.id 

这条语句会报:

unkown column db2.table2.id in where clause 

已确认 db2.table2.id 存在

大佬们 问个 PHP 动态修改多维数组的问题

Posted: 18 Aug 2021 12:52 AM PDT

$a=[1,2,3,4]  $b=[ 	1=>[     	2=>[         	3=>[         		4=>[]             ]         ]     ]         ] 

我如何通过 a,b 给 4 里面加一个值 5,a 的个数可能会变 但是不会超过 b 不考虑 a 里面的超过了 b,反正就是动态的那种

armv8 和 arm64 啥区别?

Posted: 17 Aug 2021 11:37 PM PDT

只是叫法不同吗?实际上 v8 就是 arm64 ?

请大佬科普一下 arm 版本太多看懵比了。v6,v7,v8 这些我能理解肯定数字越大越好,arm64 啥意思,它的指令集和 v7v8 有啥区别,而且我在 arm 架构的维基百科也没看到 arm64 的相关文字: https://zh.wikipedia.org/wiki/ARM%E6%9E%B6%E6%A7%8B

大佬轻喷

工业数据通信网关程序

Posted: 17 Aug 2021 11:22 PM PDT

起因也是因为工作接触了几个工业自动化领域与 PLC 通信的项目,但发现各家的 PLC 通信协议互相不兼容,而且开源的一些项目也零零散散的支持着不同的 PLC.但也有几个能支持绝大多数 PLC 通信的软件,但价格对于小项目来说还是比较贵的.

开源收费(真正项目中,这个价格真的不贵)

hslcommunication
收费软件

亚控的 IOServer
力控的一些组态软件
Kepware 的 KEPServerex
NI 的 OPC Server
使用过程中发现,如果这些软件与目前的 Web 主流技术结合的并不是很好,hslcommunication 相当 SDK,需要自己再次开发不少功能,而收费的软件如果与已有的系统衔接也各种别扭与麻烦并且针对小项目价格上极其不友好.

最终 决定自己做一款 PLC 通信程序,且应该具有哪些特性能更好的与现在主流互联网技术衔接. 欢迎各位大神讨论

奉上项目地址: https://github.com/chzhm159/IIoTDataGate

分享下自己用视频讲的前端技术知识点

Posted: 17 Aug 2021 10:24 PM PDT

我的技术博客写了好多年啦,看着自己写的内容一点点深入其实感觉还挺好的,大家感兴趣也可以瞧瞧: https://github.com/godbasin/godbasin.github.io

几个月前开始慢慢尝试用视频讲一些知识点,视频和文章的呈现感觉还是差挺远的,不过视频在一些知识点上会讲得更好理解一些,在缓慢地更新一些系列内容:

自己平时周末也没啥做的,就偶尔会整点文章和视频,不过因为都是自己突发奇想做的事情,所以也比较随性,可能不那么固定时间更新。之前基本每周都能更一些,后面可能考虑一个月一两次吧,还是得留点时间打游戏和玩猫猫的哈哈

同一个 HTTP/2 网址,用 Python 的 httpx 请求直接成功,用 Golang 的 net/http 请求立刻 5 秒盾,大家有遇到过吗?

Posted: 17 Aug 2021 10:23 PM PDT

网址是: https://www.gizmochina.com/2021/06/23/redmi-gm-lu-weibing-stylishly-teases-the-redmi-k50-series

用 HTTPX 请求的代码如下,请求成功,状态码 200:

用 Golang 的 net/http 请求如下,请求失败,状态码 403:

如果你查看 httpx 返回的源代码和 net/http 的源代码,你会发现,用 httpx 返回的就是这个页面的源代码。而使用 net/http,返回的就是 CloudFlare 的 5 秒盾页面。

有没有可以把手机完全模拟触摸板的应用?

Posted: 17 Aug 2021 10:05 PM PDT

虽然我搜到了几个手机模拟鼠标的应用,但是没有找到能模拟触摸板的应用。

win10 这几年来触摸板越越好用了,比如在浏览器内放大缩小、流畅的滚动效果等。

搜了一下 windows 外置用触控板要 800 多元。太贵了。看看有没有软件替代的解决方案。

dataloader-泛型尝鲜

Posted: 17 Aug 2021 09:31 PM PDT

dataloader

用于解决GraphQL查询 N+1 问题。

使用golangmaster分支构建。

GOEXPERIMENT=unified go run -gcflags=-G=3 ./main.go 

吐槽自己的两个开源工具(msmbps, V File Name)

Posted: 17 Aug 2021 09:17 PM PDT

msmbps 测量云服务的延时和下载,V File Name 是粗暴的基于压缩包的版本管理。

刚开始的时候,想着国外云服务是小众需求;而粗暴的版本管理,倒腾 office 文档的普罗大众都需要(它也是个归档备份的好助手)。

后面就翻车了:测量云服务很多 star,开心呀;粗暴版本管理,star 就比较少了。

我看了一下,然后明白了:v2ex 程序员很多,不少人需要国外云服务;对于粗暴的版本管理,需求较少。

小广告:
https://www.msmbps.com/
https://github.com/msmbps/msmbps
https://www.vfilename.com/
https://github.com/vfilename/vfilename
(求 star 啦)

为了深入解析 SpringMVC 核心原理,我写了简易版 MVC 框架并记录了完整的开发文档

Posted: 17 Aug 2021 08:33 PM PDT

为了深入解析 SpringMVC 核心原理,我就手写了一个简易版 MVC 框架开始(SmartMvc),现已开源并且编写了完整的开发文档

Github 地址: https://github.com/silently9527/SmartMvc

文档目录:

  • 00 深入解析 SpringMVC 核心原理:从手写简易版 MVC 框架开始(SmartMvc)
  • 01 SmartMVC 总体架构规划
  • 02 RequestMappingHandlerMapping 初始化过程
  • 03 拦截器 HandlerInterceptor
  • 04 HandlerMapping 获取对应的 Handler
  • 05 参数解析器 HandlerMethodArgumentResolver
  • 06 返回解析器 HandlerMethodReturnValueHandler
  • 07 Handler 执行器 InvocableHandlerMethod
  • 08 实现 RequestMappingHandlerAdapter
  • 09 视图 InternalResourceView 、RedirectView
  • 10 视图解析器 ViewResolver
  • 11 DispatcherServlet 实现 doDispatch 来完成请求逻辑
  • 12 全局异常处理器 HandlerExceptionResolver
  • 13 核心配置类 WebMvcConfigurationSupport
  • 14 SmartMvc 与 SpringBoot 集成(一)
  • 15 SmartMvc 与 SpringBoot 集成(二)
  • 16 SmartMvc 项目实战

简单实现一个 React

Posted: 17 Aug 2021 08:19 PM PDT

基于大佬的介绍 https://pomb.us/build-your-own-react/ 实现的六百多行的 React 简单版本,模拟出了 hook api 的运行逻辑,原理和 React 本身类似,窥一斑而知全豹 o( ̄▽ ̄)d

有兴趣可以了解一下 https://github.com/MrWangJustToDo/MyReact

ps 需要 babel 帮助进行编译转换 仓库中已经自带了 babel 的 js 文件 clone 下来直接打开 html 文件即可

包含两个版本 index.js lib.js

lib.js 自带注释和一些解释,包括一些思考问题等

index.js 去掉了多余的注释,实现了一些额外优化

有人遇到过之前买的欧洲方案 Gsuite 8 月不能续费的情况吗

Posted: 17 Aug 2021 07:04 PM PDT

付款已拒收:Visa • • • • 26,€12.58 。您的金融机构未说明原因。P0COhBip

阿里云 OSS Bucket 被墙了怎么搞?

Posted: 17 Aug 2021 06:52 PM PDT

OSS 都能墙也是第一次见,昨天好好的,早上有客户报告说图片无法显示,于是

发工单客户回复说:

您好, 由于香港与中国大陆的网络受到网络管制,导致经常性的被墙。这个对公网跨境流量而言,属于不可抗力因素。

随便搜了一下,很多人都中招了

然后想着那没办法走 CDN 试试,结果阿里云自己的 CDN 在大陆也访问不了自家香港 OSS 源站。 客服非让我开通快速传输功能,这玩意儿价格 1.25 元 /G,开了之后有一个快速传输专属的 Endpoint 域名,IP 换了当然可以访问了,但流量确实用不起,源站下行流量再加上快速传输流量,差不多 2 块钱 1G 。

那就用大陆服务器中转一下吧,居然大陆服务器内网都无法访问自家的香港 OSS

阿里云这种明明换个 IP 就能解决的问题,为何要用户自己认倒霉。

跟客服扯皮,解决方案只有新建一个 Bucket 把数据迁移过去,下行流量费自负。另一个方案是开通快速传输给贵价流量费。

分区表和手动分区有什么区别呢?

Posted: 17 Aug 2021 06:39 PM PDT

接上个话题 :彭于晏们 , 我来套一个数据库的选型方案 https://www.v2ex.com/t/795210

后来想到,系统大部分流量都是查询近期数据,所以根据时间做个分表就行了. 本来准备使用 Postgre 进行分表,但是想到了 Postgre 的分区表 ,所以想了解下 Postgre 本身的分区表和手动分表有那些优劣,另外在 MySql 上好多人都不建议使用分区表,而 pg 貌似没找到这种说法 , 那么 pg 的分区表对比 MySql 的分区表有什么改进呢?

请教一个问题,你们启动 Java -Xms -Xmx 是如何设定的

Posted: 17 Aug 2021 01:00 PM PDT

4 核 8G 我那边启动参数-Xms -Xmx 都是 4G

应用是 spring boot 没有使用操作堆外内存的情况

这样导致一个问题就是应用的内存其实不会随着请求增加 导致内存上升,感觉这样是不是有点浪费内存

本人 java 新手,不懂 jvm 我看别人复制粘贴的 jvm 优化就是初始分配跟最大分配的堆内存设置一样,这真的有效果么

安卓摄像头录制 60fps 并使用 MediaCodec 编码成 H.265 的视频

Posted: 17 Aug 2021 12:22 PM PDT

如题所示,这是我目前的需求。我目前实现到的程度:使用安卓 Camera2 API 可以实现OnImageAvailable回调函数的 60fps 的输出(即 16.6ms ),但是当我使用 MediaCodec 进行 H.265 视频编码时,编码的速度只有大约 50fps,平均 20ms 。使用 H.265 是因为博士师兄是想要用 H.265 来做,所以必须用 H.265 格式编码。

我尝试了一些解决方案,但是它们大部分都是输出 30fps,或者是预览 120fps,我想要的是编码 H.265 的视频是 60fps 。我认为我这里的瓶颈主要出在编码速度上。大致的流程是:OnImageAvailable得到 YUV 数组->转换为 NV12 的格式并送入缓冲池->编码线程从缓冲池中读取 NV12 的 byte 数组并进行编码。

我上面可能说得有点含糊,主要是想问一下大家有没有试过使用MediaCodec进行硬编码,以及相应的编码速度大概是多少。

菜鸡问题: 结构体定义在函数内部如何?

Posted: 17 Aug 2021 11:48 AM PDT

语法上没有限制. 但是我在书上没见过这么用.
为什么不这样用呢?

譬如 我想解析很多个 json 但是都是一次性的. 那我得起好多个名字.
一种简便的方式是 在每个函数里面定义一个 结构体 不行吗? 这样命名空间是隔离的 结构体的名字就可以是一个了.

Magician 发布新版本啦

Posted: 17 Aug 2021 09:38 AM PDT

本次更新主要是将 Magician-Web,Magician-JDBC 进行了一个小小的升级。

改动点如下:

  1. 修复了 Magician-Web 的拦截器,通配符过于严谨的问题
  2. 增强了 Magician-JDBC 的 sql 辅助器

拦截器的通配符过于严谨

在之前的版本中,如果我们的接口 url 是这样的: [/api/order/list,/api/order/create,/api/lottery/list ]

如果想拦截所有 api 开头的接口,大家肯定能想到在拦截器中这么配置

@Interceptor(pattern = "/api/*") public class DemoInterceptor implements MagicianInterceptor { } 

但是很遗憾,上个版本不支持,你要么 配置 [ pattren="/api/order/"] 拦截所有 [/api/order/] 开头的接口,要么配置 [ pattren="/api/lottery/"] 拦截所有 [/api/lottery/] 开头的接口,又或者像下面这样配

@Interceptor(pattern = "/api/*/*") public class DemoInterceptor implements MagicianInterceptor { } 

但是这也会有点问题,不够灵活,等于是限制死了 url 的级数,必须等于 3 级 不能多也不能少。所以新版本修复了这个小问题,现在可以这样配置了

@Interceptor(pattern = "/api/*") public class DemoInterceptor implements MagicianInterceptor { } 

增强了 Magician-JDBC 的 sql 辅助器

我拿查询举例子,以前我们写 where 条件必须这样

String sql = SqlBuilder                 .select("lottery_order_list")                 .column(OrderPO.class)                 .where("user_id = #{user_id} and pay_status = #{pay_status} and lottery_status = #{lottery_status} order by create_time desc")                 .builder(); 

这样写有三个问题

  1. where 方法的参数太长了,阅读困难
  2. 如果条件需要动态拼接就得自己定义一个 StringBuffer
  3. 最后面那些 group by,order by,limit 等都跟 where 窝在一起,有点奇怪

所以在这个版本,对这块做了增强,还是上面那个例子,我们可以改成这样

String sql = SqlBuilder                 .select("lottery_order_list")                 .column(OrderPO.class)                 // where 可以传入多次,SqlBuilder 会自动拼接                 .where("user_id = #{user_id}")                 .where("and pay_status = #{pay_status}")                 .where("and lottery_status = #{lottery_status}")                 // order by 和 where 分开了                 .end("order by create_time desc")                 .builder(); 

where 可以传入多次,SqlBuilder 会自动拼接这些条件,这样写的话,一行一行很清晰,而且如果遇到了需要动态拼 sql 的时候,可以这样

Select select = SqlBuilder                 .select("lottery_order_list")                 .column(OrderPO.class);                  // if 里面的条件只是举例子,java 没有这种语法 if(user_id 不等于 null){     select.where("user_id = #{user_id}"); } if(pay_status 不等于 null){     select.where("and pay_status = #{pay_status}"); } if(lottery_status 不等于 null){     select.where("and lottery_status = #{lottery_status}"); }            select.end("order by create_time desc");  String sql = select.builder(); 

这边再说点小插曲吧,sql 辅助器听字面意思应该就能理解了,他只是一个写 sql 的辅助器,并不是那些什么把 sql 代码化的设计思路,更不是 JPA 那套东西。他就是一个辅助写 sql 的工具类而已。而且仅针对单表的增删改查。

Magician-JDBC 从一开始就是遵循的写 sql 的设计方向,一切周边工具都是为了更方便的写 sql,千万不要理解偏了哦,^_^。

Magician 官网:https://www.magician-io.com

simplified-fetch@0.6.0 正式发布了!

Posted: 17 Aug 2021 08:42 AM PDT

以前初学 React 并使用 fetch,写得到处都是重复的配置和.json()等代码,所以有必要封装一个请求对象,去抽离简化组件内的代码,而今天 simplified-fetch 终于足够成熟,去尝试完成这个任务了!

核心功能简述:

  • 支持浏览器和 NodeJS
  • 管道式处理 fetch 请求前和响应后的代码逻辑
  • 集中的统一配置,可多实例
  • 使用 ts 开发,配合双端测试的保障

下方为 readme 简抄,预览的 md 渲染不尽人意,详见simplified-fetch | GitHub

Encapsulate a unified API request object to simplify the use of fetch | MDN and enhance it!

support borwser & node.js

Usage

import API, { urnParser } from 'simplified-fetch'  // generate 'Api' on globalThis/window/global(nodejs) API.init({     newName?: string, // default:'Api', just for global access     baseURL?: string | URL,     method?: Methods, // default:'GET', 'POST', 'PUT'...     bodyMixin?: BodyMixin, // default:'json', 'text', 'blob', 'formData', 'arrayBuffer'     enableAbort?: boolean | number, // abort & timeout(ms)     pureResponse?: boolean, // default:false, whether resolved with Response.clone(),format: [response, pureResponse] or response     suffix?: string, // like .do .json     custom?: any, // anything you want to put inside and use it in pipeline },{     someApi:{         urn: string | (params?: any) => string, // build in function: urnParser         config?: BaseConfig, // same as the above first param     },     someApi2:{...},     someApi3:'/xxx', // string as urn is supported     someApi4: (param?: any) => string, // function as urn is also supported })  // somewhere.js // all params are optional await Api.someApi(body, params, config) // enableAbort isn't supported in dynamic config 
// support multi instances by create const api = API.create({...}:BaseConfig, {...}:ApiConfig) 

Example

import API from "simplified-fetch" import type { apiF, iApi, iApi_beta, APIConfig } from "simplified-fetch"  declare global {     // unable to hint when Api.aborts.someApiEnableAbort     // var Api: iApi & Apis     // able to hint when Api.aborts.someApiEnableAbort     var Api: iApi_beta<typeof configs> & Apis }  // type your response type response<T> = {     body: T,     ok: boolean, status: number, statusText: string, type: string, }  interface Apis {     // you should type your own apiCallFunc, of course, you can bulid on this     someApi0: apiF<void, void, response<{ api0: number }>>,     someApi1: apiF<{ api1: number }, number, response<{ api1: string }>>,     // someApi2: apiF<any, any, response<{ api2: { api2: number } }>>, }  // comment next line after config all Apis const configs: APIConfig<Apis> = { // necessary to enable hint when Api.aborts.someApiEnableAbort // const configs = {     someApi0: '/someApi0',     someApi1: { urn: '/someApi1', config: { method: 'GET' } },     // someApi2: { urn: '/someApi2', config: { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } }, } as const  API.init({     baseURL: 'https://www.example.com',     method: 'POST',     mode: 'cors', }, configs)  Api.request.use((url, config) => {     // @ts-ignore     config.headers['Authorization'] = getToken('example') }, () => 'No Request')  const example = async () => {     try {         const { body, ok } = await Api.someApi0()         const { body: { api1 } } = await Api.someApi1({ api1: 1 }, 1)     } catch (e) {         console.warn(e)     } } 

Config & Ability

BaseConfig is just an extension of second param of fetch(resource [, init]) fetch | MDN

configs are listed in Usage.

{   method: 'GET',   bodyMixin: 'json',   headers: {     "Content-Type": "application/json",   },   enableAbort: false,   pureResponse: false, } 
  • urnParser & params

urnParser is based on Template strings or Template literals | MDN

usage : executed before body formatter

if typeof urn is function, then invike it with params, and build url with returned string.

if typeof urn isn't function, then try to transform params and append to the search of URL (for type Object, FormData, URLSearchParams), or append to the pathname of URL (for type Array, String, Number).

// init someApi:{   urn: urnParser`/xxx/${0}/${1}` } // somewhere.js Api.someApi(body, ['user',[1,2,3]], config) // getUrl: /xxx/user/1,2,3 

in a way, you can do anything dynamicly on url, just set the placeholder index on, pass an Array, even an Object (index need to be string like: ${'key'} ).

ps: if you get better idea or create some beautiful way to format the url, please PR!

  • abort & timeout

AbortController | MDN

const [constroller, signal] = Api.aborts.someApi 

when you use as timeout, the number is accessible on signal.timeout and (error: AbortError).timeout

  • pipeline & control

  • pipeline (Api.request / Api.response)

    • manage orderable functions which pipes before request or after response.
    • pipes with different order executed in ascending numeric index order
    • pipes with same order executed in chronological order, like queue, first in first executed.
    • based on feature Ordinary OwnPropertyKeys
  • use/eject with order

    • use: @param ...pipe - pipe[0] as order should be nonnegative integer, rest should be function(s) as pipe(s). if order is not specified, set order to 0, which means will be executed in the first place.
    • eject: @param pipe - pipe[0] as order should be nonnegative integer, rest should be function(s) as pipe(s). if order is not specified, set order to the value which means executed first or normally 0.
    • order range: +0 ≤ i < 2^32 - 1
  • PipeRequest

Asynchronous executed just before fetch and after internal core operation with url & config

function: (url: URL, config: BaseConfig, [body, params, dynamicConfig], [someApi, urn, config, baseConfig]) => unknown

only the change to url & config will effect, others are just from your init/create config & call params

Not recommended: Change anything in params[2 | 3] will possibly causes bugs

  • PipeResponse

Asynchronous executed just after get Response

function: (response: Response, request: Request, [resolve, reject]) => Promise<unknown>

invoke resolve | reject to end pipeline

Response and Request are both unique for each PipeResponse

const [order, pipes: PipeRequest[]] = Api.request.use(order: number | PipeRequest, ...functions: PipeRequest[]) // Math.abs&trunc(order), if get NaN/Infinity, may causes bugs(will executed in the last place). // Personal Recommendation: 0b1111 const bools = Api.request.eject([order, pipes]) // remove function(s) in specific order from pipeline, return true means success  const [order, pipes: PipeResponse[]] = Api.response.use(order: number | PipeResponse, ...functions: PipeResponse[]) const bools = Api.response.eject([order, pipes]) 
  • control

PipeRequest function return true or any message, someApi will immediate reject with that, don't forget to catch it.

PipeResponse invoke resolve | reject to end pipeline

  • body

Failed to execute 'fetch' on 'Window': Request with ! GET/HEAD ! method cannot have body.

fetch.spec.whatwg.org constructor step-34

so body will be auto transformed by internal function to string, append to the search of URL (for type Object, FormData, URLSearchParams), or append to the pathname of URL (for type Array, String, Number).

other methods: Object and Array will be auto wrapped by JSON.stringfy()

runtime NodeJS

  • FormData

when using FormData, please require this @web-std/form-data and set FormData global. Don't set this form-data global, and you can still use it local.

Reason: When body or params type FormData, internal core operation with url needs Web API compatible FormData.


Thanks to MDN, whatwg and Many blogers...

pyecharts 诡异问题求解,同一个图表在不同模板中渲染出来数值相反?

Posted: 17 Aug 2021 06:04 AM PDT

我做了一个记账小工具,按月把支出情况以折线图表示,但同一个图表在不同模板中渲染出来数值相反,一时间给我整懵了,不知道问题出在哪,恳请大家帮看看

在 html 模板 A 中渲染结果是这样的
A
但在 html 模板 B 中渲染结果确是这样的…?!
B

折线图生成函数如下

def make_echart():     line = Line(init_opts=opts.InitOpts(         height="400px", width="100%"     ))     dates = list(set([         x.ctime.strftime("%Y-%m")         for x in Log.query.filter_by(type_name="支出").all()         ]))     dates.sort()     outlay = []     for d in dates:         y,m = d.split("-")         outlay.append(round(             Log.query.with_entities(func.sum(Log.money)).filter(                 extract('year', Log.ctime) == y,                 extract('month', Log.ctime) == m,                 Log.type_name == '支出',                 Log.kind_name != '房贷'             ).first()[0], 2)         )     line.add_xaxis(xaxis_data=dates)     line.add_yaxis(         series_name="支出",         y_axis=outlay,         markline_opts=opts.MarkLineOpts(             data=[opts.MarkLineItem(type_="average", name="平均支出")]         )     )     return line.render_embed() 

折线图都是用同样的模板语法传进去的

<div class="echart">{{echart|safe}}</div> 

我也在 flask shell 里面运行了图表生成函数,返回的代码里面数值是正值的,但不知道为什么到页面上就变成负值了

No comments:

Post a Comment