缘起
在日常开发的过程中,经常有向移动设备发送消息通知的需求,无论是用来接收服务运行状况,还是获取及时的消息提醒,亦或者是用作接收告警信息,类似基础设施组件都是必不可少的。目前常用的解决方案包括无非包括以下几种:
- 使用电信运营商相关的通讯接口,直接给设备发送短信或者电话消息。
- 使用第三方通讯工具提供的Hook接口发送消息(钉钉,Telegram等)。
- 使用推送服务商提供的接口来间接实现消息推送(Server 酱)。
之前我尝试过用接Servier酱的API,方便快捷钉钉接收消息。但是最近好像他们的企业账户推送失效了,所以我也没有再去研究。正好手上有项目有类似监控告警的需求,所以找一个替代项目就显得理所当然了,这同样也是驱使我发现Bark的原动力。
一. 什么是Bark?
Bark is an iOS App which allows you to push customed notifications to your
iPhone(iOS Devices).项目地址:点我跳转
Bark是一套基于iOS特有消息推送机制实现的信息推送APP。只要你的iOS设备安装了Bark,那么你只需通过简单调用下Barking(我是这么叫的[]~( ̄▽ ̄)~*)接口就可以轻松的向你的设备发送消息通知,在我看来这个效果实质上是和电信运营商的短信是没有本质区别的。
总结了下,Bark有以下几点优势:
- 接入简单,所有的消息类型只通过一个接口就可以实现,只有简单存粹的消息通知功能。
- 支持通知分组、留档;支持自定义提示音;支持通知操作行为(目前只支持复制)。
- 免费、无接口频率限制,由于是走苹果推送服务所以发送大量无意义通知存在IP被Ban的风险。
总之如果你使用的是iOS生态的话体验近乎完美。Bark的通知是基于设备维度的,与接入第三方APP(钉钉,Telegram)不同的是Bark的消息不能够跨设备同步。我并不认为这是不好的体验,因为使用方可以通过扩展自己的调用代码来实现类似通知组的功能。
二. 部署Bark
项目提供公共的Server端,你可以选择直接使用,但是服务稳定性不作任何保证,因为作者本身也是在用爱发电。所以为了服务的可靠性还有敏感数据的安全性,项目作者建议我们部署自己的Bark-Server。部署十分简单,仅仅需要绑定一个域名加上Docker运行环境就足够了。
镜像Hub地址:点击跳转
部署命令:
// 获取镜像 [root@weiney ~]# docker pull finab/bark-server:v2.0.2 // 启动容器 [root@weiney ~]# docker run -itd -p 38080:8080 -v /data/bark:/data -e BARK_SERVER_BASIC_AUTH_USER=user -e BARK_SERVER_BASIC_AUTH_PASSWORD=123456 bark-server:v2.0.2 bark // 启动完成之后你可以使用以下命令检测服务可用性 [root@weiney ~]# curl localhost:38080/ping
启动服务本身并没有难点,关键在于项目启动的配置参数全部是通过环境变量来读取的,项目文档并没有对服务的启动参数做出说明。在查阅服务源码之后我将所有的启动参数都罗列在下表当中,如果你有修改默认启动参数的需求可以查阅以下参数表做对照修改。
配置名称 | 参数说明 |
BARK_SERVER_DATA_DIR | 服务地址⭐ |
BARK_SERVER_BASIC_AUTH_USER | Basic 验证用户名⭐ |
BARK_SERVER_BASIC_AUTH_USER | Basic 验证密码⭐ |
BARK_SERVER_DATA_DIR | 存储地址(默认为/data路径,为了数据的安全性需要将此路径通过挂载方式挂载到持久化目录)⭐ |
BARK_SERVER_CERT | SSL证书 |
BARK_SERVER_KEY | SSL证书密钥 |
BARK_SERVER_CASE_SENSITIVE | 区分URL路径大小写 |
BARK_SERVER_STRICT_ROUTING | 启用严格路由区分 |
BARK_SERVER_REDUCE_MEMORY_USAGE | 是否以高的 CPU 使用率为代价来减少内存使用量 |
BARK_SERVER_PROXY_HEADER | Bark服务器http头使用的远程IP地址 |
BARK_SERVER_CONCURRENCY | 最大并发连接数 |
BARK_SERVER_READ_TIMEOUT | 允许读取完整请求的时间,包括正文 |
BARK_SERVER_WRITE_TIMEOUT | 响应写入超时前的最长持续时间 |
BARK_SERVER_IDLE_TIMEOUT | 启用 keep-alive 时等待下一个请求的最长时间 |
容器启动成功之后,给服务绑定一个域名并配置好SSL证书,至此Bark-Server的搭建就完成了。
三. Bark的使用
在你的iOS设备上下载Bark的客户端(App Store即可下载),填入刚刚搭建好Bark-Server的调用地址你将会得到一个专属于这台设备的DeviceID,有了这个DeviceID你就可以向这台设备发送消息推送了。
接口文档:点击跳转
文档内已经对大部分参数做了说明,但是由于文档未及时更新,所以少部分参数选项需要通过扒源码的方式获取,包括提示音的常量参数等。本文回对相关参数进行罗列总结,并给出一个基于Go实现的请求封装示例。
1.铃声常量
package bark type Sound string // 通知铃声 const ( SoundAlarm Sound = "alarm.caf" SoundBell Sound = "bell.caf" SoundBirdsong Sound = "birdsong.caf" SoundCalypso Sound = "calypso.caf" SoundGlass Sound = "glass.caf" SoundHealthnotification Sound = "healthnotification.caf" SoundMailsent Sound = "mailsent.caf" SoundNewmail Sound = "newmail.caf" SoundPaymentsuccess Sound = "paymentsuccess.caf" SoundShake Sound = "shake.caf" SoundTelegraph Sound = "telegraph.caf" // 以上铃声为常用铃声 SoundAnticipate Sound = "anticipate.caf" SoundBloom Sound = "bloom.caf" SoundChime Sound = "chime.caf" SoundChoo Sound = "choo.caf" SoundDescent Sound = "descent.caf" SoundElectronic Sound = "electronic.caf" SoundFanfare Sound = "fanfare.caf" SoundGotosleep Sound = "gotosleep.caf" SoundHorn Sound = "horn.caf" SoundLadder Sound = "ladder.caf" SoundMinuet Sound = "minuet.caf" SoundMultiwayinvitation Sound = "multiwayinvitation.caf" SoundNewsflash Sound = "newsflash.caf" SoundNoir Sound = "noir.caf" SoundSherwoodforest Sound = "sherwoodforest.caf" SoundSilence Sound = "silence.caf" SoundSpell Sound = "spell.caf" SoundSuspense Sound = "suspense.caf" SoundTiptoes Sound = "tiptoes.caf" SoundTypewriters Sound = "typewriters.caf" SoundUpdate Sound = "update.caf" )
2.接口定义
package bark type BarkInfo struct { Body string `json:"body,omitempty"` // 推送内容 DeviceKey string `json:"device_key,omitempty"` // 设备ID Title string `json:"title,omitempty"` // 推送标题 ExtParams BarkExtParam `json:"ext_params,omitempty"` // 附加参数 // Deprecated: 我暂时用不到并不代表无效 Category string `json:"category,omitempty"` // Category 是用于对推送进行分类的,下拉推送时可以有不同的操作。现在只有一个默认的category就是下拉复制推送。 Sound Sound `json:"sound,omitempty"` // 铃声 } type BarkExtParam struct { Url string `json:"url,omitempty"` // 跳转链接 IsArchive int `json:"isArchive,omitempty"` // 是否保存 Copy string `json:"copy,omitempty"` // 复制内容 AuthCopy string `json:"authCopy,omitempty"` // 自动复制 Group string `json:"group,omitempty"` // 分组 } type BarkResponse struct { Code int64 `json:"code"` Message string `json:"message"` Timestamp int64 `json:"timestamp"` } type Bark interface { Barking(barkInfo BarkInfo) (BarkResponse, error) } func NewBark(host, user, password string) Bark { return &bark{ host: host, user: user, password: password, } }
3.接口实现
package bark import ( "bytes" "encoding/json" "io/ioutil" "net/http" ) type bark struct { host string user string password string } func (b *bark) Barking(barkInfo BarkInfo) (BarkResponse, error) { data, err := json.Marshal(barkInfo) if err != nil { return BarkResponse{}, err } request, err := http.NewRequest(http.MethodPost, b.host, bytes.NewReader(data)) if err != nil { return BarkResponse{}, err } // 鉴权 request.SetBasicAuth(b.user, b.password) // 设置请求头 request.Header.Add("Content-Type", "application/json; charset=utf-8") response, err := http.DefaultClient.Do(request) if err != nil { return BarkResponse{}, err } defer func() { _ = response.Body.Close() }() respBody, err := ioutil.ReadAll(response.Body) if err != nil { return BarkResponse{}, err } result := BarkResponse{} if err := json.Unmarshal(respBody, &result); err != nil { return BarkResponse{}, err } return result, nil }
四. 注意事项
- 自建的Bark-Server需要做好权限校验,以免接口地址泄露造成滥用
- 如果你不想丢失已经成功注册到Bark-Server的设备信息的话请务必将Bark的缓存路径通过外部挂载的方式挂载出来
- 为了方便通知的管理,可以对所有类型的通知进行分组,对于无需保存的通知可以设置服务器不保存
Bark-Server对于个人开发者来说已经完全足够了,如果你想实现消息通知回调等功能的话建议使用钉钉或者Telegram,相信后期Bark也会加上这些比较实用的功能。
共有 0 条评论