golang

分类下相关文章

Golang Gin API 接口限速

需求 在做一个基于图片文字识别的题库管理系统,使用 Golang 调用百度 OCR 文字识别接口, 但是百度 OCR 接口有调用频率限制: 免费版的 QPS 为 2。即每秒最多调用两次 付费版的 QPS 为 10 如果不限速,就会报错: {"error_code":18,"error_msg":"Open api qps request limit reached"} 而前端在上传图片时,是支持多个图片批量上传的,且会有多人同时上传。 那么就需要一个限制接口速度的功能。 备选方案 方案一:通过队列来处理,单个 worker 方 ...

阅读全文...

百度 OCR 文字识别 golang SDK

免费额度 目前使用的是个人认证: 通用文字识别(标准版) 1000次/月赠送 通用文字识别(标准含位置版) 1000次/月赠送 通用文字识别(高精度版)1000次/月赠送 通用文字识别(高精度含位置版)500次/月赠送 注意:需要手动去点击认领免费额度。 QPS 免费版的 QPS 为 2 付费版的 QPS 为 10 Go SDK 文字识别,官方没有提供 Golang 版本的 SDK。 找到一个三方的实现: https://github.com/chenqinghe/baidu-ai-go-sdk/tree/master/example/vision/ocr 但是示例代码有些问题,需要查 ...

阅读全文...

gorm soft delete 的唯一索引问题

bug 今天测试我的添加、修改接口时,发现一个联合唯一索引不生效。 有问题的表结构: CREATE TABLE `card` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `deleted_at` datetime DEFAULT NULL, `created_at` datetime DEFAULT NULL, `updated_at` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_name_del` ...

阅读全文...

gorm many2many 导致 [gopls] import cycle not allowed

今天第一次遇到 go 的循环引用问题: [gopls] import cycle not allowed 起因 新项目使用了新的包结构,每个 model 及对应 controller 放到独立的 package 中。 而不是两个大 models 目录,controllers 目录。 恰好一个 gorm many2many 关系导致两个 package 相互依赖,例如,文章及标签。 article 和 tag 这俩个 model 引起了 import cycle。 go 为何要禁止 import cycle 提升编译速度。 解决办法 Packages are compilation uni ...

阅读全文...

go gin 打印日志到文件

由于低版本的 systemd 不支持 append 记录日志的方式,所以用代码实现了 gin 写入日志到文件的功能。但是会发现日志文件只记录了 gin 路由的信息,而自己通过 log.Printf 打印的日志,并没有记录下来。 通过已记录日志的关键字 GIN debug 前缀,找到了 gin 里日志的实现。 GIN-debug: debugPrint func debugPrint(format string, values ...any) { if IsDebugging() { if !strings.HasSuffix(format, "\n") { fo ...

阅读全文...

golang 给微信小程序码图片底部添加文字

需求 由于要做硬件设备的扫码支付,生产的时候为了方便硬件屏幕上确认部署的支付码跟设备匹配,需要在微信小程序码的底部添加上标识文字, 例如设备 ID 之类的。 效果演示 还是三方库好用 https://github.com/fogleman/gg 比用 golang 自带库方便太多了。否则实现添加个文字,脑子爆炸。 字体下载 https://fonts.google.com/ 图片上添加文字,就涉及到文本字体的选择,可以在 google fonts 上根据语种需要选择字体。 实现逻辑 先生成一张白色底的大背景图,宽度为原小程序码的宽度,高度加上了文字的高度 然后将原小程序图片复制到背景图的顶 ...

阅读全文...

gin.BasicAuth 为生产环境 Swagger UI 文档加上密码保护

虽然大家都推荐将 Swagger 接口文档服务部署在开发环境,但是由于现公司前后端开发人员异地办公,我还是倾向于将 swaggo 服务部署在生产环境。加上个简单的账号密码访问限制即可。 方案选型 Nginx auth golang gin auth 最终,我选择了 gin basic auth 的方案,主要是写在代码里,省去了线上一丢丢地配置麻烦。以后迁移服务器也不用太操心。 安全问题 url 中不使用 swagger 前缀,防止 swagger 出现比较大的漏洞,被人扫出漏洞。例如这里使用了 api-doc,虽然也很容易被猜出。。。还是自己想个复杂的 url 前缀比较安全。 实现代码 ...

阅读全文...

go-swagger 生成 API 文档,及与 swaggo 的对比

go-swagger 与 swaggo 对比 最终没有选择 go-swagger,还是回归了 swaggo。原因: go-swagger 生成文档的速度奇慢无比。我一个 20 多个文件的项目,要整整 30 秒。而 swaggo 可以 5 秒完成。 go-swagger 上手困难。官方文档不友好,没有一个简单清晰的示例说明。 虽然 swaggo 格式规范丑一点,但是至少上手容易,可以直接干活。 这个文章做的对比相对客观一点: https://ldej.nl/post/generating-swagger-docs-from-go/ 再就是我跟上面作者的观点一致,就是这两个货其实都很丑陋,这样 ...

阅读全文...

使用 swaggo 及 gin-swagger 生成 API 文档

好久没有给别人写接口了,正好遇到一个前后端合作的项目,是时候尝试一下 golang swagger 的 API 文档生成工具了。 注意:尝试了 swaggo 之后,感觉很不好(注释规范口味太重,与三方库有冲突),我觉得再试试 go-swagger。但是没想到 go-swagger 更难上手,且生成速度巨慢,无法接受,还是继续使用 swaggo。 使用 swagger 的好处 返回的数据结构,可以直接引用 struct 的定义:https://github.com/swaggo/swag , 但是同时带来了问题,如果 struct 里嵌入了三方库的类型,依赖检测时会出现与 swaggo 规范冲 ...

阅读全文...

golang 实现蓝牙体征监测设备数据上报及存储的频率控制

需求背景 蓝牙体征检测设备的初始上报频率非常高,单台每秒 370 个数据包。 需要通过通过服务器向蓝牙网关下发禁止波形数据的指令,禁用掉无用数据的上报。 有两个禁用策略: 定时下发禁用指令。例如每十秒 收到波形数据时,就立即下发禁用指令 显然第二种方式更合理,而且在有多台设备接入的情况下,也方便批量下发(根据 mac 地址)。 但是,这里就出现了一个频率控制问题,就是从下发指令,到禁止成功,是有一个时间间隔的。这个时间间隔内,要规避重复下发指令。 同时,还有另外一个需求,就是对写入数据进行控制,设备方的体温上报频率过高,增加了存储成本,所以同样需要限制。 找到一个 golang 的官方库, ...

阅读全文...

调用百度翻译接口自动为文章标题生成网址 slug

TODO [X] 中文: 调用翻译接口 [X] 英文: 无需处理,参考 php 里的处理,拼接,去掉指定词 [X] 权限控制:仅限 admin 后台调用 [X] 翻译 api [X] slug api: 还是自己手写吧,减少不必要的依赖。https://github.com/gosimple/slug/blob/master/slug.go [X] 单元测试 [X] publish article page add button [X] 整理 antd form input 添加按钮的流程 百度翻译接口 https://fanyi-api.baidu.com/doc/8 免费版: QP ...

阅读全文...

升级 gopls 到最新版本

写了一段单元测试的代码,在 vim 中提示错误 func TestGenSlug(t *testing.T) { assert.Equal(t, "hello-world", genSlug("Hello World")) } 错误信息为: [gopls] cannot use t (variable of type *testing.T) as assert.TestingT value in argument to assert.Equal: wrong type for method Errorf (have func(format stri ...

阅读全文...

golang 解析 byte slice 类型的 MQTT 消息 payload

MQTT Message payload 的类型 可以看到 payload 函数返回 byte slice 类型。 var f mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { fmt.Printf("TOPIC: %s\n", msg.Topic()) fmt.Printf("MSG: %s\n", msg.Payload()) } type Message interface { Duplicate() bool Qos() byte Retained() ...

阅读全文...

订阅 MQTT 主题后,防止 go 程序退出 main

for 循环会彪 CPU,不好。找了一个 channel 的实现有效解决了这一问题。 实现代码 import ( "os" "os/signal" "syscall" ) func main() { channel := make(chan os.Signal, 1) signal.Notify(channel, os.Interrupt, syscall.SIGTERM) // MQTT 订阅逻辑 // ... <-channel } 代码分析 channel 的发送和接收数据都是阻塞 ...

阅读全文...

MQTT go 客户端发布消息

为了方便客户端测试,搭建好 EMQX 服务之后,需要用 golang 写一个发布消息的测试程序。 用于向指定主题推送消息,这样客户端可以提前测试 MQTT 相关的功能。 安装 Eclipse Paho MQTT Go Client > go get github.com/eclipse/paho.mqtt.golang go: downloading github.com/eclipse/paho.mqtt.golang v1.4.1 go: downloading github.com/gorilla/websocket v1.4.2 go: added github.com/ecl ...

阅读全文...