问题的提出

基于历史原因,公司有一个“三无”采集服务——无人员、无运维、无监控——有能力做的部门不想接、接了的部门没能力。于是就一直这样裸奔,直到前几天一个依赖于这个采集服务的大数据分析服务入口流量锐减,才发现居然是这个采集服务出问题了!而且问题不是简单的挂掉,而是这个采集服务给客户端下发的采集策略中,产品列表为空了!当时事出紧急,把所有产品开关挨个打开了一遍,算是临时解决了这个问题。事后复盘这个问题,从问题出现、到问题被感知到、再到问题被临时解决,这中间消耗的时间太长了,在新的采集服务上线之前,需要随时监控老的采集服务的接口状态,一旦有问题就可以立即处理。

问题的解决

对于后台开发或自动化测试来说,搞个监控是分分钟的事,对于我们这种客户端开发就不一样了,如果用 c/c++ 写代码倒是可以实现,但是一来慢、二来不灵活、三也不值当。于是重操旧业,用 shell 脚本搞起!话说我用的是 Windows 系统,为了在上面跑 shell 脚本,事先装了一个 msys2 系统 —— git bash,这段之前很多文章涉及过了,就不再赘述,就是对我的开发环境做个简要交待。

环境有了,现在整理一下我的思路,我希望做的是:访问后台 restful api 接口,从返回的结果中得到开启的产品数量,如果数量小于某个值,就向相关人员发送报警邮件,并记录日志。每隔一小时检查一次。

检查接口返回内容

访问 restful api 一般是通过 http 协议,这里我们选取 curl 做为拉取工具,写脚本如下:

  1. curl -s "http://***.******.***/v3/server_status?type=100&data_version=2.4"

出于安全考虑,这里域名被我用星号代替了,后面的两个 url 参数分别是请求的类型(100 表示获取产品列表)和当前协议版本号(2.4),如果一切正常的话,你会得到下面这一堆数据:

  1. {"message":"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","md5":"7cc552ea3a1f12c13f63f96f53aec29b27ab7b59542cfaac0c2938375156fdfd","result":true}

本身是个 json,有用的域是 message 字段,它本身又是加密的 (为毛不直接走 https?)。好吧,我们需要一个解密工具,对于客户端开发来说手到擒来,直接把测试用例改改就弄出来一个:

  1. curl -s "http://***.******.***/v3/server_status?type=100&data_version=2.4" | ./jq -r ".message" | xargs ./test-decode

相比上面的语句,多了两个命令,其中 jq 是用来解析 json 的,负责将 message 字段提取出来,msys2 默认是不带这个命令的,可以访问以下网址获取:stedolan.github.com/jq/download/ ,安装后将命令所在目录添加到 PATH 环境变量、并重启系统后,就可以在 msys2 系统中使用 jq 了,不过我这里是直接把命令复制到了脚本所在目录,所以需要使用 ./jq 来指明;test-decode 就是我写的解密工具啦,它从命令行参数读取加密数据 (所以需要 xargs 进行转换,不然可以直接用管道线连接啦),将解密后的数据输出到标准输出。经过上面的处理,这一坨数据就能被人类所识别了:

  1. after decode:
  2. {"products":[{"id":140,"name":"GrandDog","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":178,"name":"CubicostTRB","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":78,"name":"GTJ2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":137,"name":"GMD2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":true},{"id":180,"name":"GDraw","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":276,"name":"GLC","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":164,"name":"GUX","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":67,"name":"GCCP5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":261,"name":"GCCP6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":true},{"id":17,"name":"TME","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":25,"name":"GWS","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":36,"name":"MOZIDIFFER","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":40,"name":"GMJ","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":44,"name":"GCL2013","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":45,"name":"GGJ2013","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":56,"name":"MD_GMA","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":75,"name":"GDQ2015","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":76,"name":"GQI2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":77,"name":"GJG2015","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":80,"name":"GMP2016","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":83,"name":"Revit2GFC4GMP","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":100,"name":"GTJ2017CAD","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":112,"name":"GYZB2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":114,"name":"BIM5D_PC","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":115,"name":"GFYCM","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":125,"name":"GBCB","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":128,"name":"CubicostTAS","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":129,"name":"GMD","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":131,"name":"GAQ2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":132,"name":"GBCB2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":133,"name":"GBS2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":134,"name":"GFYC2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":135,"name":"GFYCM2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":136,"name":"GMJ2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":138,"name":"GSJ2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":139,"name":"GJH2017","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":142,"name":"TeamViewer","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":148,"name":"ZPert","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":160,"name":"GBS","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":162,"name":"GIR_C","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":163,"name":"TBQ2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":167,"name":"GYJC2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":177,"name":"GSXGZT2016","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":181,"name":"TBQD","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":182,"name":"TTED","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":183,"name":"TCFD","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":188,"name":"GSCApp","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":200,"name":"GFYC","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":207,"name":"GDQ2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":217,"name":"GO","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":218,"name":"AppGbmp","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":222,"name":"GQI2018","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":226,"name":"GDS2017","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":228,"name":"GLDTCS","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":231,"name":"TenderGo","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":232,"name":"GDQ2018","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":233,"name":"SectionManual","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":234,"name":"BeamGo","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":235,"name":"GJG2018","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":236,"name":"RevitViewer","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":237,"name":"BIM5D_PC_TEST","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":238,"name":"BIM5D_PC_TRIAL","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":239,"name":"GEC5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":240,"name":"GFYQ","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":241,"name":"RoadDesigner","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":242,"name":"CECS100G","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":243,"name":"GBES","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":244,"name":"Ceshi","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":245,"name":"dpUpdate","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":246,"name":"GFY4","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":248,"name":"GGPT","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":249,"name":"GMA2020","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":250,"name":"JZYK","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":251,"name":"GVB5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":252,"name":"GHW5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":253,"name":"GUp","aggre_status":true,"start":true,"enable_auto":false,"enable_filter":false},{"id":254,"name":"BIM_COST","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":255,"name":"GICP5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":256,"name":"bim5d_basic","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":257,"name":"GWH5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":258,"name":"GFY4_2019","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":259,"name":"GDD2019","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":260,"name":"GCCP5_ShanDong_64","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":262,"name":"GSC6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":263,"name":"GCCP6_WP","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":264,"name":"GEB6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":265,"name":"GSH6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":266,"name":"GTech2019","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":267,"name":"GPC5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":268,"name":"GTJ2021","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":269,"name":"GDE2019","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":270,"name":"CubicostTIO","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":271,"name":"GCA5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":272,"name":"GLC5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":273,"name":"GMT5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":274,"name":"GCN5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":275,"name":"GHC5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":277,"name":"GVB6","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":278,"name":"GJG2021","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":279,"name":"GJG","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":280,"name":"GAP","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":281,"name":"GSTP","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":283,"name":"TRS2021","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":284,"name":"TMEC","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":285,"name":"CubicostTMEC","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":286,"name":"GGF5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":287,"name":"GRE5","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false},{"id":310,"name":"GA_CloudPlugin","aggre_status":false,"start":true,"enable_auto":false,"enable_filter":false}],"msg_type":100}

在网页里显示会自动换行,实际上这段输出只有两行,而第二行才是我们需要的。提取第二行后交给 jq 解析出 products 域中的产品数据:

  1. curl -s "http://***.******.***/v3/server_status?type=100&data_version=2.4" | ./jq -r ".message" | xargs ./test-decode | tail -1 | ./jq ".products|.[]"

其中 jq ”.products|.[]“ 将把外层的元素去掉,对剩下的“纯纯“的内容进行 beautify 处理:

  1. {
  2. "id": 140,
  3. "name": "GrandDog",
  4. "aggre_status": false,
  5. "start": true,
  6. "enable_auto": false,
  7. "enable_filter": true
  8. }
  9. {
  10. "id": 178,
  11. "name": "CubicostTRB",
  12. "aggre_status": false,
  13. "start": true,
  14. "enable_auto": false,
  15. "enable_filter": true
  16. }
  17. {
  18. "id": 78,
  19. "name": "GTJ2017",
  20. "aggre_status": false,
  21. "start": true,
  22. "enable_auto": false,
  23. "enable_filter": true
  24. }
  25. {
  26. "id": 137,
  27. "name": "GMD2017",
  28. "aggre_status": true,
  29. "start": true,
  30. "enable_auto": false,
  31. "enable_filter": true
  32. }
  33. {
  34. "id": 180,
  35. "name": "GDraw",
  36. "aggre_status": false,
  37. "start": true,
  38. "enable_auto": false,
  39. "enable_filter": true
  40. }
  41. {
  42. "id": 276,
  43. "name": "GLC",
  44. "aggre_status": false,
  45. "start": true,
  46. "enable_auto": false,
  47. "enable_filter": true
  48. }
  49. {
  50. "id": 164,
  51. "name": "GUX",
  52. "aggre_status": false,
  53. "start": true,
  54. "enable_auto": false,
  55. "enable_filter": true
  56. }
  57. {
  58. "id": 67,
  59. "name": "GCCP5",
  60. "aggre_status": false,
  61. "start": true,
  62. "enable_auto": false,
  63. "enable_filter": true
  64. }
  65. {
  66. "id": 261,
  67. "name": "GCCP6",
  68. "aggre_status": false,
  69. "start": true,
  70. "enable_auto": false,
  71. "enable_filter": true
  72. }
  73. {
  74. "id": 17,
  75. "name": "TME",
  76. "aggre_status": false,
  77. "start": true,
  78. "enable_auto": false,
  79. "enable_filter": false
  80. }
  81. {
  82. "id": 25,
  83. "name": "GWS",
  84. "aggre_status": false,
  85. "start": true,
  86. "enable_auto": false,
  87. "enable_filter": false
  88. }
  89. {
  90. "id": 36,
  91. "name": "MOZIDIFFER",
  92. "aggre_status": false,
  93. "start": true,
  94. "enable_auto": false,
  95. "enable_filter": false
  96. }
  97. {
  98. "id": 40,
  99. "name": "GMJ",
  100. "aggre_status": true,
  101. "start": true,
  102. "enable_auto": false,
  103. "enable_filter": false
  104. }
  105. {
  106. "id": 44,
  107. "name": "GCL2013",
  108. "aggre_status": false,
  109. "start": true,
  110. "enable_auto": false,
  111. "enable_filter": false
  112. }
  113. {
  114. "id": 45,
  115. "name": "GGJ2013",
  116. "aggre_status": false,
  117. "start": true,
  118. "enable_auto": false,
  119. "enable_filter": false
  120. }
  121. {
  122. "id": 56,
  123. "name": "MD_GMA",
  124. "aggre_status": false,
  125. "start": true,
  126. "enable_auto": false,
  127. "enable_filter": false
  128. }
  129. {
  130. "id": 75,
  131. "name": "GDQ2015",
  132. "aggre_status": false,
  133. "start": true,
  134. "enable_auto": false,
  135. "enable_filter": false
  136. }
  137. {
  138. "id": 76,
  139. "name": "GQI2017",
  140. "aggre_status": false,
  141. "start": true,
  142. "enable_auto": false,
  143. "enable_filter": false
  144. }
  145. {
  146. "id": 77,
  147. "name": "GJG2015",
  148. "aggre_status": false,
  149. "start": true,
  150. "enable_auto": false,
  151. "enable_filter": false
  152. }
  153. {
  154. "id": 80,
  155. "name": "GMP2016",
  156. "aggre_status": false,
  157. "start": true,
  158. "enable_auto": false,
  159. "enable_filter": false
  160. }
  161. {
  162. "id": 83,
  163. "name": "Revit2GFC4GMP",
  164. "aggre_status": false,
  165. "start": true,
  166. "enable_auto": false,
  167. "enable_filter": false
  168. }
  169. {
  170. "id": 100,
  171. "name": "GTJ2017CAD",
  172. "aggre_status": false,
  173. "start": true,
  174. "enable_auto": false,
  175. "enable_filter": false
  176. }
  177. {
  178. "id": 112,
  179. "name": "GYZB2017",
  180. "aggre_status": false,
  181. "start": true,
  182. "enable_auto": false,
  183. "enable_filter": false
  184. }
  185. {
  186. "id": 114,
  187. "name": "BIM5D_PC",
  188. "aggre_status": false,
  189. "start": true,
  190. "enable_auto": false,
  191. "enable_filter": false
  192. }
  193. {
  194. "id": 115,
  195. "name": "GFYCM",
  196. "aggre_status": false,
  197. "start": true,
  198. "enable_auto": false,
  199. "enable_filter": false
  200. }
  201. {
  202. "id": 125,
  203. "name": "GBCB",
  204. "aggre_status": false,
  205. "start": true,
  206. "enable_auto": false,
  207. "enable_filter": false
  208. }
  209. {
  210. "id": 128,
  211. "name": "CubicostTAS",
  212. "aggre_status": false,
  213. "start": true,
  214. "enable_auto": false,
  215. "enable_filter": false
  216. }
  217. {
  218. "id": 129,
  219. "name": "GMD",
  220. "aggre_status": false,
  221. "start": true,
  222. "enable_auto": false,
  223. "enable_filter": false
  224. }
  225. {
  226. "id": 131,
  227. "name": "GAQ2017",
  228. "aggre_status": true,
  229. "start": true,
  230. "enable_auto": false,
  231. "enable_filter": false
  232. }
  233. {
  234. "id": 132,
  235. "name": "GBCB2017",
  236. "aggre_status": true,
  237. "start": true,
  238. "enable_auto": false,
  239. "enable_filter": false
  240. }
  241. {
  242. "id": 133,
  243. "name": "GBS2017",
  244. "aggre_status": true,
  245. "start": true,
  246. "enable_auto": false,
  247. "enable_filter": false
  248. }
  249. {
  250. "id": 134,
  251. "name": "GFYC2017",
  252. "aggre_status": true,
  253. "start": true,
  254. "enable_auto": false,
  255. "enable_filter": false
  256. }
  257. {
  258. "id": 135,
  259. "name": "GFYCM2017",
  260. "aggre_status": true,
  261. "start": true,
  262. "enable_auto": false,
  263. "enable_filter": false
  264. }
  265. {
  266. "id": 136,
  267. "name": "GMJ2017",
  268. "aggre_status": true,
  269. "start": true,
  270. "enable_auto": false,
  271. "enable_filter": false
  272. }
  273. {
  274. "id": 138,
  275. "name": "GSJ2017",
  276. "aggre_status": true,
  277. "start": true,
  278. "enable_auto": false,
  279. "enable_filter": false
  280. }
  281. {
  282. "id": 139,
  283. "name": "GJH2017",
  284. "aggre_status": true,
  285. "start": true,
  286. "enable_auto": false,
  287. "enable_filter": false
  288. }
  289. {
  290. "id": 142,
  291. "name": "TeamViewer",
  292. "aggre_status": false,
  293. "start": true,
  294. "enable_auto": false,
  295. "enable_filter": false
  296. }
  297. {
  298. "id": 148,
  299. "name": "ZPert",
  300. "aggre_status": false,
  301. "start": true,
  302. "enable_auto": false,
  303. "enable_filter": false
  304. }
  305. {
  306. "id": 160,
  307. "name": "GBS",
  308. "aggre_status": false,
  309. "start": true,
  310. "enable_auto": false,
  311. "enable_filter": false
  312. }
  313. {
  314. "id": 162,
  315. "name": "GIR_C",
  316. "aggre_status": false,
  317. "start": true,
  318. "enable_auto": false,
  319. "enable_filter": false
  320. }
  321. {
  322. "id": 163,
  323. "name": "TBQ2017",
  324. "aggre_status": false,
  325. "start": true,
  326. "enable_auto": false,
  327. "enable_filter": false
  328. }
  329. {
  330. "id": 167,
  331. "name": "GYJC2017",
  332. "aggre_status": false,
  333. "start": true,
  334. "enable_auto": false,
  335. "enable_filter": false
  336. }
  337. {
  338. "id": 177,
  339. "name": "GSXGZT2016",
  340. "aggre_status": false,
  341. "start": true,
  342. "enable_auto": false,
  343. "enable_filter": false
  344. }
  345. {
  346. "id": 181,
  347. "name": "TBQD",
  348. "aggre_status": false,
  349. "start": true,
  350. "enable_auto": false,
  351. "enable_filter": false
  352. }
  353. {
  354. "id": 182,
  355. "name": "TTED",
  356. "aggre_status": false,
  357. "start": true,
  358. "enable_auto": false,
  359. "enable_filter": false
  360. }
  361. {
  362. "id": 183,
  363. "name": "TCFD",
  364. "aggre_status": false,
  365. "start": true,
  366. "enable_auto": false,
  367. "enable_filter": false
  368. }
  369. {
  370. "id": 188,
  371. "name": "GSCApp",
  372. "aggre_status": false,
  373. "start": true,
  374. "enable_auto": false,
  375. "enable_filter": false
  376. }
  377. {
  378. "id": 200,
  379. "name": "GFYC",
  380. "aggre_status": true,
  381. "start": true,
  382. "enable_auto": false,
  383. "enable_filter": false
  384. }
  385. {
  386. "id": 207,
  387. "name": "GDQ2017",
  388. "aggre_status": false,
  389. "start": true,
  390. "enable_auto": false,
  391. "enable_filter": false
  392. }
  393. {
  394. "id": 217,
  395. "name": "GO",
  396. "aggre_status": false,
  397. "start": true,
  398. "enable_auto": false,
  399. "enable_filter": false
  400. }
  401. {
  402. "id": 218,
  403. "name": "AppGbmp",
  404. "aggre_status": false,
  405. "start": true,
  406. "enable_auto": false,
  407. "enable_filter": false
  408. }
  409. {
  410. "id": 222,
  411. "name": "GQI2018",
  412. "aggre_status": false,
  413. "start": true,
  414. "enable_auto": false,
  415. "enable_filter": false
  416. }
  417. {
  418. "id": 226,
  419. "name": "GDS2017",
  420. "aggre_status": false,
  421. "start": true,
  422. "enable_auto": false,
  423. "enable_filter": false
  424. }
  425. {
  426. "id": 228,
  427. "name": "GLDTCS",
  428. "aggre_status": false,
  429. "start": true,
  430. "enable_auto": false,
  431. "enable_filter": false
  432. }
  433. {
  434. "id": 231,
  435. "name": "TenderGo",
  436. "aggre_status": false,
  437. "start": true,
  438. "enable_auto": false,
  439. "enable_filter": false
  440. }
  441. {
  442. "id": 232,
  443. "name": "GDQ2018",
  444. "aggre_status": false,
  445. "start": true,
  446. "enable_auto": false,
  447. "enable_filter": false
  448. }
  449. {
  450. "id": 233,
  451. "name": "SectionManual",
  452. "aggre_status": false,
  453. "start": true,
  454. "enable_auto": false,
  455. "enable_filter": false
  456. }
  457. {
  458. "id": 234,
  459. "name": "BeamGo",
  460. "aggre_status": false,
  461. "start": true,
  462. "enable_auto": false,
  463. "enable_filter": false
  464. }
  465. {
  466. "id": 235,
  467. "name": "GJG2018",
  468. "aggre_status": false,
  469. "start": true,
  470. "enable_auto": false,
  471. "enable_filter": false
  472. }
  473. {
  474. "id": 236,
  475. "name": "RevitViewer",
  476. "aggre_status": false,
  477. "start": true,
  478. "enable_auto": false,
  479. "enable_filter": false
  480. }
  481. {
  482. "id": 237,
  483. "name": "BIM5D_PC_TEST",
  484. "aggre_status": false,
  485. "start": true,
  486. "enable_auto": false,
  487. "enable_filter": false
  488. }
  489. {
  490. "id": 238,
  491. "name": "BIM5D_PC_TRIAL",
  492. "aggre_status": false,
  493. "start": true,
  494. "enable_auto": false,
  495. "enable_filter": false
  496. }
  497. {
  498. "id": 239,
  499. "name": "GEC5",
  500. "aggre_status": false,
  501. "start": true,
  502. "enable_auto": false,
  503. "enable_filter": false
  504. }
  505. {
  506. "id": 240,
  507. "name": "GFYQ",
  508. "aggre_status": true,
  509. "start": true,
  510. "enable_auto": false,
  511. "enable_filter": false
  512. }
  513. {
  514. "id": 241,
  515. "name": "RoadDesigner",
  516. "aggre_status": false,
  517. "start": true,
  518. "enable_auto": false,
  519. "enable_filter": false
  520. }
  521. {
  522. "id": 242,
  523. "name": "CECS100G",
  524. "aggre_status": false,
  525. "start": true,
  526. "enable_auto": false,
  527. "enable_filter": false
  528. }
  529. {
  530. "id": 243,
  531. "name": "GBES",
  532. "aggre_status": false,
  533. "start": true,
  534. "enable_auto": false,
  535. "enable_filter": false
  536. }
  537. {
  538. "id": 244,
  539. "name": "Ceshi",
  540. "aggre_status": false,
  541. "start": true,
  542. "enable_auto": false,
  543. "enable_filter": false
  544. }
  545. {
  546. "id": 245,
  547. "name": "dpUpdate",
  548. "aggre_status": false,
  549. "start": true,
  550. "enable_auto": false,
  551. "enable_filter": false
  552. }
  553. {
  554. "id": 246,
  555. "name": "GFY4",
  556. "aggre_status": false,
  557. "start": true,
  558. "enable_auto": false,
  559. "enable_filter": false
  560. }
  561. {
  562. "id": 248,
  563. "name": "GGPT",
  564. "aggre_status": false,
  565. "start": true,
  566. "enable_auto": false,
  567. "enable_filter": false
  568. }
  569. {
  570. "id": 249,
  571. "name": "GMA2020",
  572. "aggre_status": false,
  573. "start": true,
  574. "enable_auto": false,
  575. "enable_filter": false
  576. }
  577. {
  578. "id": 250,
  579. "name": "JZYK",
  580. "aggre_status": false,
  581. "start": true,
  582. "enable_auto": false,
  583. "enable_filter": false
  584. }
  585. {
  586. "id": 251,
  587. "name": "GVB5",
  588. "aggre_status": false,
  589. "start": true,
  590. "enable_auto": false,
  591. "enable_filter": false
  592. }
  593. {
  594. "id": 252,
  595. "name": "GHW5",
  596. "aggre_status": false,
  597. "start": true,
  598. "enable_auto": false,
  599. "enable_filter": false
  600. }
  601. {
  602. "id": 253,
  603. "name": "GUp",
  604. "aggre_status": true,
  605. "start": true,
  606. "enable_auto": false,
  607. "enable_filter": false
  608. }
  609. {
  610. "id": 254,
  611. "name": "BIM_COST",
  612. "aggre_status": false,
  613. "start": true,
  614. "enable_auto": false,
  615. "enable_filter": false
  616. }
  617. {
  618. "id": 255,
  619. "name": "GICP5",
  620. "aggre_status": false,
  621. "start": true,
  622. "enable_auto": false,
  623. "enable_filter": false
  624. }
  625. {
  626. "id": 256,
  627. "name": "bim5d_basic",
  628. "aggre_status": false,
  629. "start": true,
  630. "enable_auto": false,
  631. "enable_filter": false
  632. }
  633. {
  634. "id": 257,
  635. "name": "GWH5",
  636. "aggre_status": false,
  637. "start": true,
  638. "enable_auto": false,
  639. "enable_filter": false
  640. }
  641. {
  642. "id": 258,
  643. "name": "GFY4_2019",
  644. "aggre_status": false,
  645. "start": true,
  646. "enable_auto": false,
  647. "enable_filter": false
  648. }
  649. {
  650. "id": 259,
  651. "name": "GDD2019",
  652. "aggre_status": false,
  653. "start": true,
  654. "enable_auto": false,
  655. "enable_filter": false
  656. }
  657. {
  658. "id": 260,
  659. "name": "GCCP5_ShanDong_64",
  660. "aggre_status": false,
  661. "start": true,
  662. "enable_auto": false,
  663. "enable_filter": false
  664. }
  665. {
  666. "id": 262,
  667. "name": "GSC6",
  668. "aggre_status": false,
  669. "start": true,
  670. "enable_auto": false,
  671. "enable_filter": false
  672. }
  673. {
  674. "id": 263,
  675. "name": "GCCP6_WP",
  676. "aggre_status": false,
  677. "start": true,
  678. "enable_auto": false,
  679. "enable_filter": false
  680. }
  681. {
  682. "id": 264,
  683. "name": "GEB6",
  684. "aggre_status": false,
  685. "start": true,
  686. "enable_auto": false,
  687. "enable_filter": false
  688. }
  689. {
  690. "id": 265,
  691. "name": "GSH6",
  692. "aggre_status": false,
  693. "start": true,
  694. "enable_auto": false,
  695. "enable_filter": false
  696. }
  697. {
  698. "id": 266,
  699. "name": "GTech2019",
  700. "aggre_status": false,
  701. "start": true,
  702. "enable_auto": false,
  703. "enable_filter": false
  704. }
  705. {
  706. "id": 267,
  707. "name": "GPC5",
  708. "aggre_status": false,
  709. "start": true,
  710. "enable_auto": false,
  711. "enable_filter": false
  712. }
  713. {
  714. "id": 268,
  715. "name": "GTJ2021",
  716. "aggre_status": false,
  717. "start": true,
  718. "enable_auto": false,
  719. "enable_filter": false
  720. }
  721. {
  722. "id": 269,
  723. "name": "GDE2019",
  724. "aggre_status": false,
  725. "start": true,
  726. "enable_auto": false,
  727. "enable_filter": false
  728. }
  729. {
  730. "id": 270,
  731. "name": "CubicostTIO",
  732. "aggre_status": false,
  733. "start": true,
  734. "enable_auto": false,
  735. "enable_filter": false
  736. }
  737. {
  738. "id": 271,
  739. "name": "GCA5",
  740. "aggre_status": false,
  741. "start": true,
  742. "enable_auto": false,
  743. "enable_filter": false
  744. }
  745. {
  746. "id": 272,
  747. "name": "GLC5",
  748. "aggre_status": false,
  749. "start": true,
  750. "enable_auto": false,
  751. "enable_filter": false
  752. }
  753. {
  754. "id": 273,
  755. "name": "GMT5",
  756. "aggre_status": false,
  757. "start": true,
  758. "enable_auto": false,
  759. "enable_filter": false
  760. }
  761. {
  762. "id": 274,
  763. "name": "GCN5",
  764. "aggre_status": false,
  765. "start": true,
  766. "enable_auto": false,
  767. "enable_filter": false
  768. }
  769. {
  770. "id": 275,
  771. "name": "GHC5",
  772. "aggre_status": false,
  773. "start": true,
  774. "enable_auto": false,
  775. "enable_filter": false
  776. }
  777. {
  778. "id": 277,
  779. "name": "GVB6",
  780. "aggre_status": false,
  781. "start": true,
  782. "enable_auto": false,
  783. "enable_filter": false
  784. }
  785. {
  786. "id": 278,
  787. "name": "GJG2021",
  788. "aggre_status": false,
  789. "start": true,
  790. "enable_auto": false,
  791. "enable_filter": false
  792. }
  793. {
  794. "id": 279,
  795. "name": "GJG",
  796. "aggre_status": false,
  797. "start": true,
  798. "enable_auto": false,
  799. "enable_filter": false
  800. }
  801. {
  802. "id": 280,
  803. "name": "GAP",
  804. "aggre_status": false,
  805. "start": true,
  806. "enable_auto": false,
  807. "enable_filter": false
  808. }
  809. {
  810. "id": 281,
  811. "name": "GSTP",
  812. "aggre_status": false,
  813. "start": true,
  814. "enable_auto": false,
  815. "enable_filter": false
  816. }
  817. {
  818. "id": 283,
  819. "name": "TRS2021",
  820. "aggre_status": false,
  821. "start": true,
  822. "enable_auto": false,
  823. "enable_filter": false
  824. }
  825. {
  826. "id": 284,
  827. "name": "TMEC",
  828. "aggre_status": false,
  829. "start": true,
  830. "enable_auto": false,
  831. "enable_filter": false
  832. }
  833. {
  834. "id": 285,
  835. "name": "CubicostTMEC",
  836. "aggre_status": false,
  837. "start": true,
  838. "enable_auto": false,
  839. "enable_filter": false
  840. }
  841. {
  842. "id": 286,
  843. "name": "GGF5",
  844. "aggre_status": false,
  845. "start": true,
  846. "enable_auto": false,
  847. "enable_filter": false
  848. }
  849. {
  850. "id": 287,
  851. "name": "GRE5",
  852. "aggre_status": false,
  853. "start": true,
  854. "enable_auto": false,
  855. "enable_filter": false
  856. }
  857. {
  858. "id": 310,
  859. "name": "GA_CloudPlugin",
  860. "aggre_status": false,
  861. "start": true,
  862. "enable_auto": false,
  863. "enable_filter": false
  864. }

然后就可以得到下发产品列表中的产品数量了:

1 lines=$(curl -s "http://***.******.***/v3/server_status?type=100&data_version=2.4" | ./jq -r ".message" | xargs ./test-decode | tail -1 | ./jq ".products|.[]" | wc -l)
2 # each item takes 8 line
3 prods=$(($lines/8))
4 echo "product count : $prods" >> log.txt

没有找到 jq 怎么输出 json 数组元素个数,这里直接用 wc 计算行数除以 8 (每个产品占用 8 行)得到。同理得到密钥的数量(每个产品一个单独的密钥):

1 lines=$(curl -s "http://***.******.***/v3/server_status?type=101&data_version=2.4" | ./jq -r ".message" | xargs ./test-decode | tail -1 | ./jq ".keys|.[]" | wc -l)
2 # each item takes 4 line
3 keys=$(($lines/4))
4 echo "keys count : $keys" >> log.txt

这两个数量必需一致,且大于某个域值,这里设定为 100.

 1 limit=100
2 if [ $prods -ne $keys ]; then
3 echo "product count != key count, fatal error" >> log.txt
4 send_email "$prods" "$keys" "$limit"
5 exit
6 fi
7
8 if [ $prods -lt $limit ]; then
9 echo "products list too less, warning" >> log.txt
10 send_email "$prods" "$keys" "$limit"
11 exit
12 fi
13
14 echo "gux server ok" >> log.txt

如果有任何异常发生,通过 send_mail 函数来向相关人员发送告警邮件。

异常情况下发送报警邮件

铛铛铛~ 进入本文核心,现在如果接口中的产品数据为空或减少到特定值(产品一般只增加不减少),就需要通过邮件通知相关责任人了。这里使用的是 sendmail 命令,在 msys2 环境中,没有自带这个命令,需要事先安装 Windows 版本的压缩包、并设置 PATH 环境变量包含该命令所在的目录,重启机器后就可以在 msys2 环境中直接访问了。这里给一个下载链接:www.glob.com.au/sendmail/sendmail.zip。注意这个命令只是模拟 sendmail -t 选项,并不是原生的 sendmail 命令,但是用法和原生命令没什么区别。在开始看 send_email 函数之前,让我们先了解一些基本原理。

邮箱工作原理

你通过 qq 的账号给 126 发了一封邮件,它经历了哪些流程呢?请看下图

抛开复杂的协议不谈,单说整个流程,就是你先通过邮件客户端把邮件发到 qq 的邮件服务器,后者通过地址路邮给 126 的邮件服务器,最后你的邮件客户端再去后者的邮件服务器里拉取收到的邮件。对于 sendmail 命令而言,最主要就是进行发送账号的各种配置。

配置发送账号

在配置发送账号前,我们先选择一个可靠的账号,这里我选取 QQ(不要问为什么,问就是请参考附录)。首先登录 mail.qq.com

在邮箱的设置中找到账户相关设置,开通 IMAP/SMTP 服务:

开启后可以获取授权码,一个账户可以获取多个授权码,用在不同应用里:

出于安全考虑,这里把授权码隐掉了。

配置 sendmail 命令

有了账号和授权码就可以配置 sendmail 命令啦,下面打开命令目录内的 sendmail.ini 文件,加入以下几行:

 1 ; configuration for fake sendmail
2
3 ; if this file doesn't exist, sendmail.exe will look for the settings in
4 ; the registry, under HKLM\Software\Sendmail
5
6 [sendmail]
7
8 ; you must change mail.mydomain.com to your smtp server,
9 ; or to IIS's "pickup" directory. (generally C:\Inetpub\mailroot\Pickup)
10 ; emails delivered via IIS's pickup directory cause sendmail to
11 ; run quicker, but you won't get error messages back to the calling
12 ; application.
13
14 smtp_server=smtp.qq.com
15
16 ; smtp port (normally 25)
17
18 smtp_port=25
19
20 ; SMTPS (SSL) support
21 ; auto = use SSL for port 465, otherwise try to use TLS
22 ; ssl = alway use SSL
23 ; tls = always use TLS
24 ; none = never try to use SSL
25
26 smtp_ssl=auto
27
28 ; the default domain for this server will be read from the registry
29 ; this will be appended to email addresses when one isn't provided
30 ; if you want to override the value in the registry, uncomment and modify
31
32 ;default_domain=mydomain.com
33
34 ; log smtp errors to error.log (defaults to same directory as sendmail.exe)
35 ; uncomment to enable logging
36
37 error_logfile=error.log
38
39 ; create debug log as debug.log (defaults to same directory as sendmail.exe)
40 ; uncomment to enable debugging
41
42 ;debug_logfile=debug.log
43
44 ; if your smtp server requires authentication, modify the following two lines
45
46 auth_username=2057975342@qq.com
47 auth_password=*****************
48
49 ; if your smtp server uses pop3 before smtp authentication, modify the
50 ; following three lines. do not enable unless it is required.
51
52 pop3_server=
53 pop3_username=
54 pop3_password=
55
56 ; force the sender to always be the following email address
57 ; this will only affect the "MAIL FROM" command, it won't modify
58 ; the "From: " header of the message content
59
60 force_sender=
61
62 ; force the sender to always be the following email address
63 ; this will only affect the "RCTP TO" command, it won't modify
64 ; the "To: " header of the message content
65
66 force_recipient=
67
68 ; sendmail will use your hostname and your default_domain in the ehlo/helo
69 ; smtp greeting. you can manually set the ehlo/helo name if required
70
71 hostname=

文中标黄的就是我们要加入的配置,这里授权码同样被我隐掉了(哎呀,邮箱暴露了~)。命令配置好了以后,就可以在 shell 脚本里调用 sendmail 命令了

使用 sendmail 命令发送邮件

终于可以回到我们之前提到的 send_mail 函数了,它有三个参数,分别是产品数量、密钥数量和最小限制值:

 1 function send_email()
2 {
3 pc=$1 # product count
4 kc=$2 # key count
5 lm=$3 # count limit
6 from="2057975342@qq.com"
7 # for multiple receiver, not work
8 #to="yunh@******.com;anlj@******.com"
9 # using an array of receivers
10 to=("yunh@******.com" "anlj@******.com" "yuyf-a@******.com" "duanxd@******.com" "zhangcj-c@******.com" "linc@******.com" "sunyd@******.com" "zhangb-l@******.com")
11 subject="gux server exception"
12 content="gux restful api exception: \nproducts: $pc \nkeys: $kc \n\nproducts count != keys count \nor products count < $lm !!\n\n\n"
13 mail="From: 'gux monitor' <$from>\nSubject: $subject\n\n$content"
14
15 for var in ${to[@]};
16 do
17 mail=$(echo -e "To: <$var>\n$mail")
18 done
19 echo -e "$mail" >> mail.txt
20 echo -e "$mail" | sendmail -t
21 }

获取各个参数 (line 3~5) 用于后续拼接邮件正文 (line 12),对于 sendmail 命令来说 (line 20) 使用 -t 参数后允许将所有参数通过一个格式化的文本来设置,这个格式类似这样:

Subject: title
From: sender@mail.com
To: receiver@mail.com
Cc: copy@mail.com body...

由两部分组成,邮件标题由 Subject(抬头)、From(发件人)、To(收件人)、Cc(抄送)……组成,两个空行之后是邮件正文。上面大段代码都是在设置这些内容 (line 6 ~ 13),注意为了减少对我 qq 账号的关注,这里对 From 域设置了别名 ‘gux monitor’,这样收到邮件就比较直观啦。下面是一次真实的报警邮件:

另外对于群发,不能简单的在 To 域设置多个接收人,而是要分别对每个接收人进行一次单独的 To 域设置(允许多个 To 域),这里使用 shell 数组对收件人进行了遍历处理 (line 10,15 ~ 18),最后一次性发送 (line 20),下面是打印到 mail.txt 里的邮件原文:

To: <zhangb-l@******.com>
To: <sunyd@******.com>
To: <linc@******.com>
To: <zhangcj-c@******.com>
To: <duanxd@******.com>
To: <yuyf-a@******.com>
To: <anlj@******.com>
To: <yunh@******.com>
From: 'gux monitor' <2057975342@qq.com>
Subject: gux server exception gux restful api exception:
products: 0
keys: 0 products count != keys count
or products count < 100 !!

注意由于遍历时是向邮件头添加 To 域,整个收件人列表是呈倒序排列的。然后效果就是上面截图的啦~

设置定时任务

最后就是把这个脚本设置成定时执行的任务了,这块可以参考之前写过的一篇文章 《查看博客园积分与排名趋势图的工具》,第 3 节。下面是经过一段时间后,脚本输出的日志:

2020年07月 8日 16:00:01
product count : 103
keys count : 103
gux server ok
2020年07月 8日 16:55:15
product count : 103
keys count : 103
gux server ok
2020年07月 8日 17:00:01
product count : 103
keys count : 103
gux server ok
2020年07月 8日 18:00:01
product count : 103
keys count : 103
gux server ok
2020年07月 8日 19:00:01
product count : 103
keys count : 103
gux server ok

……

2020年07月13日 10:00:02
product count : 104
keys count : 104
gux server ok
2020年07月13日 11:00:01
product count : 104
keys count : 104
gux server ok
2020年07月13日 12:00:02
product count : 104
keys count : 104
gux server ok
2020年07月13日 13:00:02
product count : 104
keys count : 104
gux server ok
2020年07月13日 14:00:02
product count : 0
keys count : 0
products list too less, warning

输出太长,中间有省略。可以观察到 7.13 日 14:00 有一次报警 (不过后来证明是一次乌龙,汗~)

结语

后来查出问题的根因,居然是采集服务在和产品中心同步产品时(管理员登录的情况下),如果后者恰巧挂了,会导致前者同步不到数据,就会把所有产品开关重置掉!一个隐藏了 3+ years 的 bug 啊,教训深刻。不过话说回来,不管代码怎么 low,接口监控是不可少的。除了用来作接口监控,我还用 shell 脚本给其它服务做简单测试,例如验证升级服务能否正常下发版本、验证用户中心能否正常登录等等,凡是通过 restful api 提供服务的,基本可以通过 curl + jq 搞定,甚至通过 tcp 长连接实现的消息推送服务也可以用 shell 脚本来验证。不过这一系列的内容,因为涉及接口安全,我没法提供 git 下载地址(压根没有相应的 git 库),望大家理解,有需要的同学可以照猫画虎,把里面的接口换成自己能访问的,来动手验证一下。

参考

[1]. 在windows下配置sendmail服务器

[2]. Using Sendmail on Windows

[3]. Linux简单配置SendMail发送邮件

[4]. linux shell 发送email 邮件

[5]. 不可或缺的 sendEmail

[6]. 配置mail命令的IMAP和SMTP,接收邮件和发送邮件

[7]. shell 发邮件命令之 sendmail

[8]. jq : Linux下json的命令行工具

[9]. 使用jq工具在Shell命令行处理JSON数据

[10]. 命令行 JSON 处理工具 jq 的使用介绍

[11]. shell脚本处理JSON数据工具jq

[12]. HowTo: Install jq

[13]. https://github.com/stedolan/jq

用 shell 脚本做 restful api 接口监控的更多相关文章

  1. 用 shell 脚本做自动化测试

    前言 项目中有一个功能,需要监控本地文件系统的变更,例如文件的增.删.改名.文件数据变动等等.之前只在 windows 上有实现,采用的是 iocp + ReadDirectoryChanges 方案 ...

  2. Postman如何通过xmysql工具的Restful API 接口访问MySQL

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 导语 有时候用 Postman 接口测试需要获取MySQL的查询结果做接口输出的校验,这里介绍下 Postman 通过 R ...

  3. 使用Flask设计带认证token的RESTful API接口

    大数据时代 Just a record. 使用Flask设计带认证token的RESTful API接口[翻译] 上一篇文章, 使用python的Flask实现一个RESTful API服务器端  简 ...

  4. Spring Boot入门系列(二十)快速打造Restful API 接口

    spring boot入门系列文章已经写到第二十篇,前面我们讲了spring boot的基础入门的内容,也介绍了spring boot 整合mybatis,整合redis.整合Thymeleaf 模板 ...

  5. SpringMVC Restful api接口实现

    [前言] 面向资源的 Restful 风格的 api 接口本着简洁,资源,便于扩展,便于理解等等各项优势,在如今的系统服务中越来越受欢迎. .net平台有WebAPi项目是专门用来实现Restful ...

  6. Java 调用Restful API接口的几种方式--HTTPS

    摘要:最近有一个需求,为客户提供一些Restful API 接口,QA使用postman进行测试,但是postman的测试接口与java调用的相似但并不相同,于是想自己写一个程序去测试Restful ...

  7. 初识restful api接口

    一.restful api接口举例 实现功能 传统方式 restful方式 url HTTP方法 url HTTP方法 查询 /user/query?name=knyel GET /user?name ...

  8. 整合swagger2生成Restful Api接口文档

    整合swagger2生成Restful Api接口文档 swagger Restful文档生成工具 2017-9-30 官方地址:https://swagger.io/docs/specificati ...

  9. Spring Boot入门系列(二十一)如何优雅的设计 Restful API 接口版本号,实现 API 版本控制!

    前面介绍了Spring Boot 如何快速实现Restful api 接口,并以人员信息为例,设计了一套操作人员信息的接口.不清楚的可以看之前的文章:https://www.cnblogs.com/z ...

随机推荐

  1. C++类重载函数的function和bind使用

    在没有C++11的std::function和std::bind之前,我们使用函数指针的方式是五花八门,结构很繁琐难懂.C++11中提供了std::function和std::bind统一了可调用对象 ...

  2. 博主心酸历程:初始Hadoop安装安装过程出现的各种问题。

    首先,作为一名第一次安装Hadoop的小白,费时六七个小时终于安装好了. 如果你是一名小白也是第一次安装,请参考以下教程: 链接:https://pan.baidu.com/s/1pwu6_znWKz ...

  3. 【NOIP2014模拟】高级打字机

    题目描述 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: T x:在文章末尾打下一个小写字母x.(typ ...

  4. iptables防火墙说明即使用

    防火墙是架设在公网和私网之间的服务器,隔离公网和私网,保护私网. RHEL7默认使用firewalld作为防火墙. 但firewalld底层还是调用包过滤防火墙iptables #systemctl ...

  5. mysql1045问题解决

    输入mysql -u root -P 1202 -h localhost -p时报错mysql1045 解决方法:my.ini中加上skip-grant-tables后重启mysql服务即可解决

  6. 整理的网上的MySQL优化文章总结

    MySQL优化 Linux优化 IO优化 调整Linux默认的IO调度算法. IO调度器的总体目标是希望让磁头能够总是往一个方向移动,移动到底了再往反方向走,这恰恰就是现实生活中的电梯模型,所以IO调 ...

  7. Redis哨兵模式(sentinel)部署

    1 主机环境 我这里使用的操作系统是centos 6.5,安装在vmware上,共三台. 主机名 IP 操作系统 用户名 安装目录 node1 192.168.1.101 centos 6.5 wxy ...

  8. 快速排序之C实现和JS实现的区别

    快速排序是面试中的几乎必问的问题,理解之后发现并不难,在此贴出两种版本,与小伙伴们相互交流 PS:今天码代码非常有感觉,所以连发三篇博客,下午打球,手感也是热的发烫,希望不忘初心,方得始终. 进入正题 ...

  9. Redis Cluster集群架构实现

    Redis集群简介 通过前面三篇博客的介绍<Redis基础认识及常用命令使用(一)–技术流ken>,<Redis基础知识补充及持久化.备份介绍(二)–技术流ken>,<R ...

  10. junit源码之Runner

    Runner 定义了执行用例的执行器方法. public abstract class Runner implements Describable { /* 获取描述 */ public abstra ...