用 shell 腳本做 restful api 接口監控
- 2020 年 10 月 13 日
- 筆記
- curl, decryption, jq, msys2, restful api, sendmail, 學以致用
問題的提出
基於歷史原因,公司有一個「三無」採集服務——無人員、無運維、無監控——有能力做的部門不想接、接了的部門沒能力。於是就一直這樣裸奔,直到前幾天一個依賴於這個採集服務的大數據分析服務入口流量銳減,才發現居然是這個採集服務出問題了!而且問題不是簡單的掛掉,而是這個採集服務給客戶端下發的採集策略中,產品列表為空了!當時事出緊急,把所有產品開關挨個打開了一遍,算是臨時解決了這個問題。事後復盤這個問題,從問題出現、到問題被感知到、再到問題被臨時解決,這中間消耗的時間太長了,在新的採集服務上線之前,需要隨時監控老的採集服務的接口狀態,一旦有問題就可以立即處理。
問題的解決
對於後台開發或自動化測試來說,搞個監控是分分鐘的事,對於我們這種客戶端開發就不一樣了,如果用 c/c++ 寫代碼倒是可以實現,但是一來慢、二來不靈活、三也不值當。於是重操舊業,用 shell 腳本搞起!話說我用的是 Windows 系統,為了在上面跑 shell 腳本,事先裝了一個 msys2 系統 —— git bash,這段之前很多文章涉及過了,就不再贅述,就是對我的開發環境做個簡要交待。
環境有了,現在整理一下我的思路,我希望做的是:訪問後台 restful api 接口,從返回的結果中得到開啟的產品數量,如果數量小於某個值,就向相關人員發送報警郵件,並記錄日誌。每隔一小時檢查一次。
檢查接口返回內容
訪問 restful api 一般是通過 http 協議,這裡我們選取 curl 做為拉取工具,寫腳本如下:
curl -s "//***.******.***/v3/server_status?type=100&data_version=2.4"
出於安全考慮,這裡域名被我用星號代替了,後面的兩個 url 參數分別是請求的類型(100 表示獲取產品列表)和當前協議版本號(2.4),如果一切正常的話,你會得到下面這一堆數據:
{"message":"MjllcG+T6g4UJWklDvBu3wq5D8ClRoHuUFFlepFL9xnoEdCHU1J8VLnN4GvaMv4FcareEbznrpp60fyXkr1MSFrSz6P3eUCPFUorS2w0NfhfHKfdXz1lzhV29LTFOc9rYNxOLO2RAswyrN6CmAYsVMBoNrPIq3uA50ymLbJFhsnWqOpIBofhdEnDzkS0T+BBX112Nbw46prknIqY0UJW60aMnLuPVmjJKEAxWCgfCLrWDp0ts4uaTbvV8nvi7U+bS9Oqxz1fNC40SfNcc2bLILZ8ZZ4givi2SwfHPs0mN6fF/ewACKzykjuIf6+xVfTnQBFZGiNLunKSz0fiNJXj226CMTVx2KNMG+lHJgYqHpXxLiMcvbj/herzN0gINGEUExZ5GDNBYFph1MD2q6jUqtWwFGlSVRqi4Mz0FyCx6ADRB9SrZjopEYmFFtqkc6QvxQeC+xgNmGu91vkW9o7rADkblQPetNjouJ2WfBH1WXB9Rm7mbIo5YKVrIABXo9YLkdELnZsaNlx/KOg0cazqwMyemlwI7+PexaB6gZQqYqL6Awx3+KptARPNib0mFeetMqPiJkl+S1gNaiQ7I74YK7vzFDVDQjLCupTYoILlIewMHGqLmvnOnWNpI4ZKVVOPSUZpa73hzJfGuMN9jCuybOeTxR2JD1HX2+teA6Lr8mYGu9KW70guKtRvvP0VM2/DmGb9K57jWzJjaSngsffo4yY/gM0wqg6HE3QczHXdhdiOpT3jfghfV0DG6dkcxL8lADjBR1W9pGAHObKcY7iIBiIH5Jcm/oK9nFFCsG3+QAzrJv+NyPtyCBJ/R9c5r3ihGK3+wDqudExy2JjmGC7FZdWqSSIcp2OXrQOBAC9+7BZW/qbJZpD6pcHOfFTRoYYxAVhkhxkHxca/OhSntxA158mN55RMl8rb1o0kJzli7Cty0HZiXbEqLKL5mH5vJDW2dGDPr7JtnolpP2MUDWJdBjH4WiIeqxB3bplEecvVWPtgDbq/8r0XamToOzRnn9X7gmdcWpjoP6oeLYFw1v7PgvcBr2SCxwif1zLBiXDEizDJ7V2kK1zs0DpiDVrota318624zkVosxHEvaidtJhthlGu+qBTWVY2fwbYncatlZ/5WbHpowzHreE1C3bFn94G4xjYZlCpQqoFgQI/EoU/Ml2uXRISj53a7NVp1OMzZu6gkSJ8AQH44OxJAo3+tYlu6tdYOie2LNnIpSyfrHmxv7MliulK85kSRyA+/IrKMSz91yC7zrIzPPSYwWXu+pX9eiWRFuMxezFmYkZwqCVvea6yVvpNBOI5BQPtVQyzjdd9b0iCUtujNBJY4TH+Pxw9O7chyc4lmoL3H0DH+ofwkJ9xtK6YR/ygDH3CwURq4TS6SVIm8L/NOpF9lHbMU/TWdeMGYXrAMgZzgAQwMF2s4Cs51FNrmKsx3zUBQva9JpJue42G/Imj3tdReI0CGlmAxV72q1h+t1KiW0nNSre5J0ZTkXEGO6Usx781k1X1p8MmzW1Qyj4hLJpevr7s7ahLpwlfeblCA4mhC1UGe9xKSpEhvINgOVXCdX8qfNv+iwojVl8pwRfnLo4IIH0LuZRFw3Rn3UVJKGHLdyRHcf4zOQz8y4Rwe5EsC9aMWWImQD2Wx9XVKZP6kZs4WcQHlkodg9AXP0yAqmurPBmDa/nEH3/VkYfohqU2xOniUXhtcupA/eUMEcdxvB2dhNeuGZ6OWXTtW9NWF1DA30u1o/GzYSdMbAqXfeCX6E4T82xl6mc9let84abAT1YFvOcnFcC92bT4XFxnbZut6DYs4F6fdznrdR3j33ua+V8Rbrk+Fm6xJWLJEbsUAQA9EO5ebfD1UG5zHbbEMTgNl9auwgRG+znBBSmdFH7XAdogJbDEtiRQG1uBM6d2DQDfW2dXoHfHTYMZB+cxtwEEZxo3iqNGoRMknpr/EcWuqJN4slzYT0ckd2VYNJaVmwU1ukEGmgk0dY0hmUmR+K2NG6ETMbZYQCSAoGvXgRjrjbXZkFz0SzA5aNKBnlmchWnpMZAKhn2DPkedloW+oNN4AAs/S0lg4I1BbJ27jMc7As+fGxbprstsHnCesLvSt+yewg7eWdEb2FAEPiVuwGd91xeZAjqCgcfgruxQ8gBPcnA3wISUipd6IITHF/4pWDh4bCbfm/plJex4sLff4rlvDpu01e/hLsfiDKJ4CHXeZXU8+3iRdG+BEIeSV9X9RmXW70M4lrIsdWCRYUOPuZ4swnVCsgLnnJVt14drWwF9gE/dAwUbsiCypLCqNjNf314Qkn3B9sXOF4s/HjifLLC2I6StX411g9uC0rIjMw2iJeDH6NmROm/dRVMkzkhzlVrEM4d9nSwBFZpMq4kTxMHgLJmUPQG8Qu40Rd/qQ46d7JLyBZsVH3+E5B/Dv9X5KyIWKP59XAc9uPtfiLK+HWnG5clChWjG1uAGrYGGeP1J8iCtaw03GPieKFYEox9vKICjs+x/FfWeLjrB66TwvMYlsEl/2t2OomJ7qnQXY2bQPlCYeuCgZf7Amvc3CKgKrSkQCMMO4uIBmHdyJeYctUV4VlkVE1BFN6MRyIIwXmQy7xdQb5yBFNl5FO1td1zn8Cm+Kkklpjpwtg6G6QGGqX0jQvEmL0dxUMzHgkumxAgSIm7iB6ndD65Z13NKOIplb7Nn8kYX4b43t1lkkDOtcpGcx8LkZZU1sf+C+/bWQKuyL1LC5Wg4rIjy0UA78fq1gG6KAGCXP8AGEL5l6rHg9La+NVI/LzdQwlEjAhQ7DBIClwrk943H1vapdEpMktGUHLZahoEL7CKSbe3vO5l62rVujsi5W9rmH3/DtS90dErXhrIidjyrGm+u5JdcIpbaP+qKwzgd/XEkU5YxqbJ2RgzuXRQpxtAVfptlU8PYj0FH0Fzs67dE0uestXcVTudThTxZ0NbxJ45u3KX9WqoAOf6UyO0XpwJAuPbiH3d+gISYznEXlzsf6kZ4fc6z6eUX+F2UPIQ/JaoK0VpTlV35VbjSOsSSQ7Dcb4VzO8WlMiAV4B0oVaJuAnie/R2InbMkaoxthhnooPue5TliJdPAcDP6aeTOlvhcvhY/0bPT32kECIZPJrO3S+9snwqR2Qw0LuYuJwibjw3HdMqG6t4Wt+qiDbRj8sWMXXk8uPDthXUDqCwMETwBNQEQAf2gue72gFGho9qPyBm3PirjiUHjSEImQTWCzcMGQZE+lIVP/2cQExe4+hdMcjPTnUu8Xx4tqKIjgliPJyLx/NouFB5JXniHCI281e0IDxRM4gGsuGGe4z1I0bGU3UAhd2xA4akw7PnayAZ+jSm5xSy/bjtgoGuxegD4B8SoQzPYTsp6Bz3y6g7jPEWpvKqM12HJru7RsCVBPtO2SQ8nIjmdDuRo/Q6mzNHOiTnBUzfGNYK0AJPaJ4M5sHdaFcYjSRVgSFfzs9Fnz5pA1Nt7vLNCe3GSacXqdd6+VqrTb81Slfkac0OwNeCrNwiJUIo0UW2kTGU2tz9AXp7h2s31eBxrPNB0/jKE7TmnRRgOUBeB0GeglV9sJVZJqR8Zwgj8noJH7RFN3rzvtFfMElJGyAEKb7ip2egCCrs3745jrwdMt9wTQP+XXqegmlXqJEi9bcJaSXpHmy76cOpabK9L/WZfOKncFo0TNq4Gxdx/nYP9j1SW7NHHvjuZ16/YWcJLDh0raK8Qfa0TPOnmXSyppDzE0GmzIjdJC1UntefS0zy7aYfhJ2EDukWq1QdEN/nEdZzGt8LrNQ6XhzpyuOdaKq1HN/JgddEjROJrviglXUdL6LO/x8ioiH7+oFv6hw39puL/9OUzMOe6jFR7baPLcaFHlnyy2S3xc1DTGZGsNczNkSRId69uOvKTMwPlYEiL38JyIeBG4csKHP3/fjmbaZes4skqbccB0q+KBO/i0/7ZzhE5eZc/BLu0bfr1qAsAC0lYR2+rxZF86tAu6wcpGtMtsK/QHYgtB7e1DJEsqx7R1ZpIdbAVS/FI1BELn84n78NGzLEkulAWqUGTMqd1bqEk2YtqEpP2bLZmGBZQpcGFGBvu1TVaPzYbCNEA57YWK0BSOvUWy9H5+s8b4XcNfVFf6nBPpAycwJDy93MEK1BGc3gnQFb4m8ptnRr7qjgsCE22yOcKdYeri2ZzDlDLs35bVc/aAF2ZI5iZV9XLASgEsqerRJwAuzKdU0VMUm9tNO7MQwCPL0Gln1Mh4gqqzv4BTctWPVw7vnvioLLw5E2NmuFNl/CiwiQIWTIaHyvSCQyf/7wUxKlQi/YF4LhFZfkKZUqkXmqPQQFKZU5oW8Og6bkFx479G/XWPbZSoGE2LVza/RyfMTPYyHi1guQz/t8f+8r92GWTBEM1dlWpMRkqZ5PqKomfexnsoQaLx05DnYGoAj3b9y5bzJEglH5e2+31cjoM4t3aTMpMu3azdQTcq/zluSkLIyxZ8A8GEx6ns3zpbssISD3PPs4OVWRfCSums7miktgTw3iulexCvYxg10MermiwxGRjuU2ajcq4ph1KGPcWj/XAZFNHdnzwAtPxJnRyIJE3W0r4ZNoCXYbrlBdzsZRic9SBJouEOf3P+9TzlltBACAH6yVfRrwflZPGLqT3ISZG5rXg8s/F5aFN24xHU3VKC+py1OqXYgkWfbsAFakHWw+XHIIJwGjpnqL/OIxYF2ibXWDAXFKwQXqssJ7OGDXTLVnV+Txhpj1LQKtCGjx+w44y+ovBhhD15/xuA/zZ/Xfp8K+O0ziMqx+yPkR762B7HjX8G1k9oJaVxkSffiBtqnHCGDeX6V0D/10A40d8gnfnBQbOIlAEWs05QtqrjmMXRoxUOGQbCtRwr84dEKfe6fw4P3CtDL+tT6Q9pyANL/92+WxVXC2v3ng88BgOf+XihZGq0Bjn/Fi78GsIZ4kCkrKDsmZo6pV8vWmytLjvw1jsGqej+QgFLFKPcZjp859+j/iRnTVHjcSp29koDjX6tSpFPU+rFHSeNb6WvKmjFtwjdPkcHMzE4dY86UcpdlqrgRVZbOzthnDAeXAB+qOgvvjKYYasnVDjvdpoqC8Zf3ekX27T/AaH8s2fmnPCsXjr+sOlr7Rn6zCtvzCfp4iIl1EN8XTTmlgIzQprcRFSEbp210k3GNkoDVSgVRHxFrdxnq5dAGwbJbtGuoFmenIf5LlCiByDkjEN982/V59cxpO8V5N2xiOZP7enKSbNrzEd6OvAsuMs1gaJbJB42r22udwFZl/4R0cC5bpYlPiNuDsMwzaxCvBXMRbGv6h+25FooEGfgHKmO+Kb78zBR9aN5D9p1nJdMhqKkMf2EtqJvwBYOEKWbUBj/AE5054/lN9WqCxnszrVaOv50tF+bcRfwI9+LbVvxZFNsOwe0o5eGXB2LWJ+mX3qo3nGnsGnBKY4VZ+kAA/+DTyWIZuSfA5utZ7sQUEODYagwBPbaXsJr3EVVhGYgk5GQod7Bqz3GYM8aBC9kM/WN/jtDu6rzjDMvws7hJ2ZQhmTXHksNCOakhjejUfioj3I8w1I/rZfvILDujxUSv3neSUE0mZzaduup0SWeRUP49etR7WwwOEl32Qa06StGrv4rPkA20u0fgwcLmdT+0JsI6RPypAjP1ubuzpiaMKGfXKosqJR5TC1Xua8CX+su6wkl2eltKpO2VyJffNoJ8ZQsoiJ5Ab4NUa+oiD7MFwh/lLldyo6LeKLbOJ02mmvNo1Z7z5w+tAH7NJjDa1wLtw25oNl4gdlD2ZEnY6U35PLko1WQsCQ5ylitH6yNPuRG2RXmbsh/lnA8fB9aoXFbnuyMYsxdCTQoLKagGzIkW4kVUloiE0JFmcW0sC5OOT4n2m6vivuMUJCcvuJFdFl3Jt5Ku1+gRlzXuW5u0ZVFSodMaLkajDnrh8DXZbGs5ObzxwxEbl6DJ5LYwsYdt4+eq0yOSQ0dAzocECe5CLyB0tpRIjAYUJ/vV3wk5IEtEHfS+sQemlQ2m91Ey2VmFdwPhlgRVhFLJ0OaYmdtPOzfYV512oKhjq1PWtRdru6N0kbWrmdbUkEHcBVI8caiWOl8sKG6MY5F+re/wkTOxQPXyZin31PwF5ccqcir+4ESJay35TeKELT4LwZR5aUFpz2Jqj/HkHeGZmU1T2C9zL0DUa95lEMvMDrdal6JZXh7Vff75TuwOEhlr/j1qg3Ma7d3VWZSatsT0/sJbeMypWTRXoah1EkvviG6HzPG7MiWpLivm8mp2kTxvc9IV+B26jVm+Cir/AU69DDlrr0sJA0PnpsumWlJU8toZY5nNtlmOetQOvwAaqwewQN0xlNdsAKUOtNnmzdgshQY3862HjU1Yla2MnkACjxh2Gr4BAG2TJzbkRePe1/3cyWLAtm24WK85rWFVJKA+o/XY9yC+y/46u35NlXUpC0+q3Mg94txC+cWCeOXCC1GrepQL64A7JUE/YlKOKrxGCPaAaG5yXB1o7rbY56MCHTcFwZQWMwTxQG6bhIlmRz5c/WfO/7jeUXkl6GHd/hIoz9MOsD7GLjpPBFsqGjtbgeirg9B3umUT8CxG6p5Qp/2z6HZVrD4przwA5tG77RgACgWOYtAxwnHA49kEbFQdwnrbi+dawPZfawhJg2wW6QvjEmJe+W1zsqiTC3BUyd9YM+/XcygZlZgxjIQfKuhlzHc3SNv+W4NRCAjAs1n+zNGjTKTSc/6tB/eAYAxPnZLOnYTsvjC+Zn3Aa62HZcCnwSCbYGNEpz7yB3v5v5iGhplaoU3BOzItg7KKI6uheXepUar61GWm9SJLGZ/ur2cPFrlIkSa8MYHpqAuOzKXcT+1R6QtDBayKVTHlVfL3K4t9SM9/4IVcg+IypFhzCa7CK8ugEYsSDLktLtEo65+33V14GLLKZGcy3DvhdiOHGPaeNGy9huAtcfOdFybUbjsGFSbbphdd0/A5YhzuVRigT4jUxgTgdZtlLBbighDBclHMpzB/nBaqwTmGwMgfNNYdwPjc9hkTdjYs5y3ZV3EIKHIxGtDOgG096LvEQKknw48JEyFWySD/wHoe//ewl4PN+zXXSqw78HiQvK2/AWUBE4jq8ACdC1qHIO51c3hKNZXvpDhuzwhTs+kjAUPvMeyKvyGv8sJZivW2j3GvVkDYrQxM6DgupTK09Yn7E5/XUNa4Wt9nw0mX1xVOryNXUeU7xa/vh7LISW/62s96ds8T0lIyK2c6weLTnz/zDHC+lHJlxRQmL024jAyrPQA7Lx4hhUckPbN6E5pOsUVVu3yDtP/+Wm/r2IYohAd1nYO3LKN4bmlg0gjeoZd72Xmnyn69EdDpjyjrFoDeFfLs7iq4xSs9xcdCXb1yD+aLAzT8VPVG49s44FwxADJgCI1iK9q2LwaNakXY+THcuL56FmcQobOvxhUeSyGpyu0elA1STXbPJc2flfBKhQkOZVlcXeeS2N4oLkhgq1Z2bVNltUkwT879sSPtUVsNW9/Qwgq+4QytnGTGByYHOnStA/PfAIItu+hqusBh4amVocJfz0tYvKysUyqNwKY+sqhkT6qEbgvT+/qunsOSwy2RkzusOdVYBDrdP0KFDnfaTXhNpss79GdzMZr/aNK+mSeO1FYTITv1dCJNqNN1MEQ//o2t6S3ONkoos6MwMldWF0EqqpEQjES2nT1mq2jYPsp4Mb4kQBeAixQ9Y5lCTnJ6TAyaYObhj/bliEWHjRGxTcEII/ytJIBVVV153ONkCOyGD67XpEIsZiLY2K9zrBtlOLLCCzrxX6CB/KQsdoT57/sVNdrG4gDHqQrDB9+0bm5KCz2KWy5/mb3EVML+NjwBq6eZLM7PJEkWCeUjAH0b+FjUUPWs9PVt4OrB2jgg4EZZliFzjhQw+kmySDhXdj2/FHtWB/YFgPyuQQWSkxX2pPMB1nYIjqT/MsN3cZLyD/5yu/+BjfgbsQVrMRjy4dR1pY7ZjG+qcX498dj32iGVyk8z5B2bsUFUo6Bu71e2SheWw0j3VwVsazVC7UMgzO1QWsQyGlwxR/Bh0Ct3NlQqUyw0JA7Ty0G9xFEXoQMy+vtNR5LRAJALKMjcVuI8bNRLgggdna/SLL2YSnO2mIR58Y4cHYjjrpUlaiLI78bqn2NKvkawl2ok80sIHepCzZykPu6c6lgGam9yq4Xch1OSAT5+o8+nMQV3unjUBTP5Ew7Gy/U1Zuf/47/QfdeCC4lMFXjBlcULK4zoceLWTh1zjZYlByQPq2U7+MU3NnIzEuI6v1hwKcb66qqWYvFEQFW6L+FgaST5aaawH8OVqMxA5pO75Vv96sq54f2KVN5Mh82hzATw4XHJPu49zjx3I+fDBwLFV3zHQJD/qGCcQl/R9HgJR19BGaYQH6minuaK9fXb1apKAxnhZfm9vcIaT22fhh1rAVLHUJKqoKT2dx7rfUrNAYrw8pDgj3JidlXlDFuqmScJHhrYelPIdGWUmjpgqH/UFIBB63hwAKAZBzlYRFXCU661bJVja3QD/XFafwLqTX8BvTRqQNQcmExDEk4wWgBU61v2/dwPpYLoW/qW+kGiG/cmTFbN7hXGWnTp6lOls3O3ggXIGj+1sx2T3Vdptq7SrEGDpstFcSPo7lxMVOuew73s9opZXOu2mtUe7DIcsicvJifsBUAlxDlHdAbO4fTG1kXF0v5ybqrkRaadDBU4F775h+rNPLB+ziL6achTKk3iVsSnWbrZfha2bgWWG2j9YM22vxy6VaiJbL9ZEHHeiv0LmViz7888iNI+LXxSDI4XCmLHmdQNLk/NNpLAiYDzCl9lbxC5iFvABsaZigBuCqfc/EzqLNqSrHL4sugvUmY0rlqs7oh0OQnKiWJdIlDTQpo/cEmc4NA8SkBJ9qLl2poP8EvpOUyHCZUSl0jinzNe+abAiyEzbD75ynac9VJuouk225cozgTsUlklmj/RpKoYxopmLMm+xJfkC2NO4vlQpo42C/KJvMhQK4S32NVngSyhF4rhrkTC28hcBzdQsrsyMQKHygH13YoKRlXZCUoXzuFgMPBmqfWoc138oLYd4DNc9sqZhT8MTdw3OW9WOZNwsxPktVIXxqZdRkmkGXB/Pt/uoXZ2F+OBhxFXyViwrhzqiIKw2KItKpPsdXW4iPuUrMx/a4JjNIKcIGbZx4zkdCJtqCQ6BAD18deDfS0NOnZJZ1mymAvWmDxdwU9zapBcpyVMCm6Ep0I0q+pG+PQo60wz5MC+8IlLY7dHP0uC4rSaXM/WATMGkSjQnnEb9GIdo5UbtdMCutoLF4K7tSIR1OUk4I4PJYn0xpPAbHBzm9gGJ408xN3oe0+DR7Do80H04MA0S9IodQWCAhKFY3MUulg7F3bDdHIUlzYJEDDKW+y6eVjfYRe/6fnT2lneqw57alb9KnlM47OHJr4qnnoE+oMSSSnr94KqRnudcA+Ln9Pj/UTxbFrYQAsEywPaXnEKO9qZSEVc/W81oP+gUgrG5zCWHYoSiZ5rwBlExGpHObXbvaLehuGBFXCe2dl7bk3wnkh2qK+1XHEHKf07midYc88bH4BerV1llc0HNWgvWQd2P/RkQPgePAVZ652p5PinZCk8ubOW1zuVa0t7eRn0w7layAHIf3Xody/g0+e0v7AaQarxZBfdcQmb/aFjGi1KCAOlnKNrWIb5zr3MN5q0L/h9WguM4MeBUZqzfND9BTH26wImlyp2uItCRJWYM7bQm4t4FcKMjkEKvj01wcJMd5bTScj+0BGoRHWUyQxRRlm2cVR2r1/bB3l7Dv+DXkKECARa+RRars9ftPEUkArdjbbWkBQJhCQSdeNR3Ym6mW82QAqBLXEN1FTcEtwMwcfy9Ep+kP6yKYgZI/NK9pW2A838xhe71+3ul6/5xpZ3zMG4gYGJDLYgu54gSFM6bDe7gIs/tWer1o8uGD1q5OpDVZnpxMHsJl88XvPuUSkW3L1YcjxG4YFAYtfYAd1yNhjUDqCeE8xIQXb1QI6KkpHtWOJno5C5kwhdie3BIpE0Tlrq3zbBB9BUTG3mJoBe0Db6Ti+QQpw5h4ospUfIH4R2HHHzi2tvZ3ew6V3xvNUBb/ZYfia1PRumG6EY759IC5Y/PjfB4pbPxgxfLPT2ywe6d/7UXplckeadRxS194/dtP3eUiLgAfS1rHI1H/qdYG+xLHD+nRMB8D7gLWlM8rrcIPBiFFNAcBwZEVRyr25LXrhjI6mxsQSxlHTqnf8iLZId2DUKaBI1G69mrzof3DD92LJKqD297EoYXqoSvt3nElOuzofSPiw7FsOeLGbZzFtAH8xMwZvTyN0NYLHyBMMdmocCwbeltpOhCApl0eNYDOngVAygoojQbS4hDFywmi2+WyfXRh6Vm9p0acjRDY/jOhpsizVff7TuSrDWcMalkXafclL90AWRFU7wmc5Z9R2QIQVgBHAKnr7tQhgwvjPwktzvdV7y6HHDwXFt4iAF2SlywyDKlGSHM2ppr71hxROyHweSJOVLAwKss6NQnZiKXqjDF+NQxdIWfb2qjCVFhrBLtsXld6lolBS8k0dyHQ8zuuF+BmDQHslYtzyZrPzF/zxFsOq0TGWIBXeamUevno59TsuopIcss1IBXFxWXFO2CFCuht5iOtGAGaYL8gFB/YBRCC5yPjmzn9J5m2ZEVXYHt/1Uol0eHsgle/rfede0VCZpmmN0AYLx2zo9676CDmkq6wAlGKD5fz62qbwR6tK1XUAbVrGYhr7SEvsXTEEvsqLERSDgiSj6ExAWdbeAFxrDZN85UXHVWhtcVcBy+qcxPj53F3nXXkRb0QAiGe8HD9uB6JOa3pPsOduI7n8hRkhwxJrUAHFJKk4as8zMjP6Syadp59cnS+uNMh0KdNAbD5LfzzSahOANUtDhYhnWDWkMuZDfxUNMiIWzOet/w92PYBO2GuaKfRnY7yRE9bWea3vh4hHZvnN8unYEzORBnznUGSsvnfneypLEvdD5TZWJdpNv8GJPhngHR+p4euALzbjN3t8fJAYUBt8XIBN4rO0JAXMGyfv9FlD0Cdu6i3qoePgg9J06m74Q5rzul2XmZHoAv+QGrozfqrSK+ooOanVTR35hlO/fgrZ44Sl65Ux0tcveHETgZhzEGJj64bhQYexEdYviFFuNXRUv1et35RniFsToEUOINjRUYJy1aJGhx7T9GtUWMRmVcw1Ma5BKMYJMSIPZhYggn/bR2DbDVMQqwK9E8P+ynhJFosWggfBgoyN9FGk8Z+Q5lYd+C5ME1rE1PyghAjQFDfkhyCA0j5wcpIFt0AiMn808fsKAMXP26ztiSgdlz2HVBrWzkrVKqNgnT4eJika+RxV8pDrmY+VEtccQYonh9RLmE9xi4Ce51++4SgIrF+lhPaU9PNVni2wqGQELVsHQl1PR3vtEz+M4SAlGFPx6qTfNualKef89JrPiOrIpBbYlSA31zuqyiie/0/5wununc475Fn43nVezHNe07HiLEqLwENqJgWSt+EnLLP6XS1Qb7b/iGP98DxbX+FhLy6OOVuiS6wOcBrE3rxn2cXqSgjtPa3fqbZTc9XeXhuK4HoT721qGJxoMwslHEgfNFhHbwsHhwnRIGSH/uMvLSPFAhxYE4qdReITMLN2cNwsC+sP/sgPwPVH7UOqP2bPpFma2+CEMMGlVf8DaHEZEOUph6qkfUGHDXe9OkVmYWAxwcZVMdEfDR7EHIdvSGSy2462sp1Kzhzq4k65DsfvzMD1HxEWauj8BqD9qbbNLSkI48hznylKjdSIQBQvaV0Rg0wKIWvkIH73SYYJm4wR/ISUQ5GXMJLdKxQFGVKe7zPyQ6gb3CcJj0fnMlKJmoVamnk2X9fefpzw0qBfXCSwD3CV3TjbbgjqczmzLwE3v+YXt234uX9hLtIXxn6nMESe3ICBG5FhGH9Dm8iaydk/FJQ/LRJFbnRBao2wqIvPrGh4mzCI6C0yJ17+yuLUjfWlDEmJnIaWmm6AJMf+SPxX/w/CDj4U30kwU+Xw+OEy7X/ibiqJuivT/JgSEt2CKW1DaLUZwzuLwj4oLHrhtX0bW5ur8vk5mby8llz2rkJVng3FhojsD2AECCDbXBnD0sNZAXJSz+fhx/MHLgRJNfX7h7wf1sZcp5BSMUXlN7kcEbrCxqsrshHHNZNsSIJhggbCU4MldbNaKZVRhKAdv/2UE2jEazHPoyIPClO8sNEhryd4ffmay5wI5qsSUcDWL0Sq0BwwdRthSUODmu6GF0XkaKGwSPiTcFmwMeoNB2DVW3NmHkeJFQ0weNCTnRwKYvIUbm4cARywVLUWvXg2adubypykGtyB8pmQUcpHWL5oo0MTg/lkP8svIz4qWOb37Lk+j0e4usLlhICWq22jtSbZbtcC9DxNUSb3qy7Fj/dEiPB2TBXlYwAjpMqpWh9K0kkbBwLkikOiHAKLJYE3I83FQMkc5NtIpCKULeTZksnNM9H4G1rD0pk4o+U5f+B2NJ4A2QhOfJRJtrJkO/2HMcka942YhLHnU5Vz7aY8OjgEac/OzEXpaJOxWlt6VMNjwkpbrOsf4t1Idip0y1OZg4x4DnW3mDASrhXvbFB95bhZSRACYj2nGVBk607xqlYTAZWrkPYUjYdXpYxmrJsLUoAL3VYp1hhVHEqzfb8jdz6i5j+6lYNarBUGPsuSE49h234Toi0pzhnXFiOEiPgP2zr8ct0qAesFktDArffy3bQU2Zogl0m+0/iGhpikSFOXwgWHC0k81qoWpKA0Qej1NsWKJlkqx2JiQXouZa3hE4BqK/QhO2VxYZQDx03PlwJdSLN2KkrhoNBo3XzcwKlhakNvTwcOi5OIZV9rJEGL+fMii6hyG8kxatocnR01H6XvdzcclDQTqNpXURPXJcVxwPh68IPK28qtmolUfwcVEdTzr7uljJSEXQ7UWqV+tCFEOcryNYHpO3gQ79IZ/2WmtnXaLS2pPXHdgMI07bUfXN3TLitkVarvewULFYqoIGdspdP4F5hkG1ROzictHaK0EK1JlWiFMlFxXJa10lwy3TMd/VUzFTOaaPDvXCcCf7Sj1rl09ks0OA0WnLSAn2kDTy/TcaH6Ohp72HCCYIOYJNkP2MXbDGZ5sVkuAgDdomSQJNe+6dBxoVvWwzmlBfnF0GeVpcSieCLYmzMdZohOBhGGKRzaqdqemMNeQA03+kKQdXVTLEmhWH25AOVMLQd5kY6DqKYBlJIyFFAePRTbIk8V7QNKEv8/6YsUvTECSjacCcVeSTv3B4cLLR4ndu4kHVBlGaT/YkzlKxZVcVA3ZMmjAVWIAH2cKLLuP03LvqRNwfaMXQ6HMEtSmoBFwZNn99tQCOgBJJkMe96CHnEpWhnKsPy1LdQ7cwPdQUT7qojZrW038nvbVp0O/RdBkMhqJNr8MMaUYbAnf6dgT9FdVrux/MA2jxaMJH8jjqUkaY8KM58mRfiCr0MwwJNAY+NWRVliAq+q8mtuY8Io6COAZL/c+wzglyKOSozbCK5VjsqWBJrXYia2JNbz5aixoVD4+BCVeowjDRgwkVyCEToXbfTq6xriwu/WMYjp7/RshjdCwqsrJeJNlmEcEBr5vF/BdsNIVOn6uH2mjTMsjNW29Z7/Yx9n203JKSbnocsIcCdOnyjHZwD7BncPFvSUOCJxwsHFSqardmn4yX/KzCV38wwSSYL0kU1kPSTHD1OT9nisxqcMqqXHFm84/VBD+UyOi4fummpW4RX81bksVPoai36mAYqqDaca6EAO0T/fVyRnn/tNEM7T6Pp9zibVidEGT0N/ei3/xn4MnfEmMev3101tHdYAWAnfa4BICsjsvCTy+OVcKd0nOvfXrEpKnDibH0N4fiOjaQfpQ5n8DCV/QJXZRHe73SqysVxl0p1eiNsmwpkJ0726LnRD6WRCXqgvDHIH/WxPtB8mXxxdUIP31K1pZ/sXdtrDejXMuSg3GPcWtFda+dl32mluveOhDWEh+xa13zOkm607CVMx/sIQDaH42N6RGTn9Q4goIUTAhGY5lQ2N459PnyU2v2DGQyvZ8GzlLGofN/Nk+c/UvHXeKLLG6WBghCE0mBdPjKh9TYGvyEVSykmf42Nu/Eqp8vLEpZfveGYzh9cd7uevL8JweL1aS8BEWSUMcA943E2VxaqUG/P44F0jsnVlWy+gw2p930VIl2W8PgwRsJZvKX3PUB7HVvETlnUzq1i0vGtE2o5SHhcgCi0OlBmAsARKxWolMIdw/HAnYwR17Io2Is30+UbO1pdV5FJTgyFucP48lplxyaJZSHGEMDoL2rALaneFeox/rqGJTwZ1AlupkgT6ELnvTLlfe1If+dJIDSLYixos+mrvcoNXmOqohachyDirqzMQkfBu9Q46Z+V4V72mSeJICBkaylrrmYtjDF9LyevU9Bighqzehae/T2AhSgUk5CHROV/xx7ZGaC/Ff6E0MqFMjOm+i2EI/PLj5cl0ivLp0QrlFgHRmmOi1sc+pOOrc6A4VQ++q78giMGpGuspOZXLyLwwfceac7z5+zB838H5uM2H5chB022KACBTx9PyVOutXMAShdgQz479JFXJtKaP0KipaO1YSfkEP+B2KIfA805CPTG4uHmt3saNq+hAq0qu7MgnF0MwS5YAGWmrVZqCrbN70MbI20VwZ11KzIayVNIXnK/rV7hQMHRDeZs50R5pwf+6kIY/mgRdPB7SQLT3t954hqmMpgOeFcW2u0RYhR04Y5V2p4gpPAskTbylyXrT87C5/VOwrQgWfGCxwllyLbJyXVy2eu0nGMyTKHF1nnpWuFZrpVt1wg9Albl7ZGyOkVxrzGGG4cassB43piu8/mH1NvFYMONefpRarmLuCAVZvUi2aq1IYQgsfNuvsyCOFrw8b/837DYYAMyVbvEU6VoTHoTY4HuGeYAs72+c3iS6sKVr4g+QtUzbF/KncUqOeDQoHmdZbQGajbu","md5":"7cc552ea3a1f12c13f63f96f53aec29b27ab7b59542cfaac0c2938375156fdfd","result":true}
本身是個 json,有用的域是 message 字段,它本身又是加密的 (為毛不直接走 https?)。好吧,我們需要一個解密工具,對於客戶端開發來說手到擒來,直接把測試用例改改就弄出來一個:
curl -s "//***.******.***/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 進行轉換,不然可以直接用管道線連接啦),將解密後的數據輸出到標準輸出。經過上面的處理,這一坨數據就能被人類所識別了:
after decode: {"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 域中的產品數據:
curl -s "//***.******.***/v3/server_status?type=100&data_version=2.4" | ./jq -r ".message" | xargs ./test-decode | tail -1 | ./jq ".products|.[]"
其中 jq 」.products|.[]「 將把外層的元素去掉,對剩下的「純純「的內容進行 beautify 處理:


{ "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 }
View Code
然後就可以得到下發產品列表中的產品數量了:
1 lines=$(curl -s "//***.******.***/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 "//***.******.***/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="[email protected]" 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: [email protected]
To: [email protected]
Cc: [email protected]
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 庫),望大家理解,有需要的同學可以照貓畫虎,把裏面的接口換成自己能訪問的,來動手驗證一下。
參考
[2]. Using Sendmail on Windows
[5]. 不可或缺的 sendEmail
[6]. 配置mail命令的IMAP和SMTP,接收郵件和發送郵件
[10]. 命令行 JSON 處理工具 jq 的使用介紹
[11]. shell腳本處理JSON數據工具jq
[12]. HowTo: Install jq
[13]. //github.com/stedolan/jq