本文介紹使用全靜態頁面的網站如何利用騰訊雲的 SCF+API 服務實現簡單的後端接口,並提供了一個 Python 出題器的實例演示。javascript
相關服務介紹:php
雲函數(Serverless Cloud Function,SCF)是騰訊云爲企業和開發者們提供的無服務器執行環境,幫助您在無需購買和管理服務器的狀況下運行代碼。 API 網關(API Gateway)是 API 託管服務,提供 API 的完整生命週期管理,包括建立、維護、發佈、運行、下線等。html
前幾天爲我家小盆友用 Python 寫了個簡單的自動數學題出題器,小傢伙十分好奇,隔三差五的就要來讓我演示一番 😏。只是每次都要拿本出來輸命令給他看實在有些麻煩,因而想着能不能加個前端頁面調用,直接打開頁面就能看到運行效果。前端
做爲一個行動派派,我目標鎖定了用 SCF+API 的方式,也就是如今很🔥的 serveless 方案。最大的好處固然是不用再伺候服務器了,少了不少搭建的麻煩。並且這個按實際使用量計費,對於小網站再適合不過了。java
下面介紹下要怎麼實現了。首先,你要有個騰訊雲帳號,而後參考👇的簡單步驟:node
照着這個文檔 雲函數快速入門 按裏面的步驟來建立本身業務函數。第一次能夠選擇使用控制檯建立函數,運行環境中選擇本身熟悉的編程語言,當前支持 python, php, golang, java, nodejs 幾種,而後就能夠在函數代碼下愉快的開始了。這裏以運行環境 Python3.6 爲例。默認的入口函數是 index.main_handler
,有兩個輸入參數:python
不清楚參數裏有什麼的,或怎麼用的,能夠直接打印出來看看,都是 dict 類型,一目瞭然。建議加上傳入參數檢查和限制,畢竟咱們不知道調用接口的人會傳些什麼奇怪的東西。返回類型包裝成 json 格式,對前端調用更友好。給出改好的代碼👇:jquery
# -*- coding: utf8 -*- import sys, getopt, random import json def main_handler(event, context): print("Received event: %s" % event) print("Received context: %s" % context) params = event["queryString"] return auto_cal_generator(int(params["limit"]), int(params["op_count"]), params["op_type"].split(","), int(params["total"])) def auto_cal_generator(limit=100, op_count=1, op_type=["+"], total=100): if limit>999 or op_count>9 or total>99: return "exceed max input limit" res = {} res["msg"] = "Here are today's %d works, good luck!" % total questions = [] l = len(op_type)-1 for j in range(0, total): up = limit question = "" for i in range(0, op_count+1): num = 0 if i == 0: num = random.randint(1,max(1,min(limit,up))) question = "%s%d" % (question, num) up -= num continue op = "+" if limit - up > 0: op_i = random.randint(0,l) op = op_type[op_i] question = "%s%s" % (question, op) if op =="+": num = random.randint(1,max(1,min(limit,up))) up -= num elif op == "-": num = random.randint(1,max(limit-up, 1)) up += num else: print("operator error: %s" % op) sys.exit(1) question = "%s%d" % (question, num) questions.append("%d: %s=" % (j+1, question)) res["questions"] = questions return json.dumps(res)
寫完 code 後固然不能忘了最重要的測試工做,代碼輸入框下就是測試的入口,須要建立測試模板。系統已經預置了好幾種模板類型,直接拿來改爲你須要的就好。咱們用 API Gateway 事件模板爲原型修改剛寫好的出題器的測試模板。因爲咱們 code 獲取的是 event 裏的 queryString
,這裏只用修改裏面的 queryString
這塊:git
"queryString": { "op\_type" : "+,-", "op\_count" : 2, "limit":100, "total":10 },
建立完測試模板後,點擊左側測試,瞬間返回結果:github
返回結果 "{\"msg\": \"Here are today's 10 works, good luck!\", \"questions\": \"1: 76-4-44=\", \"2: 52-42+67=\", \"3: 95+4-50=\", \"4: 84-78-1=\", \"5: 29-20-9=\", \"6: 19+37+38=\", \"7: 93-53+57=\", \"8: 80+7+7=\", \"9: 90-74-11=\", \"10: 7+34+52=\"}"
結果下方還有執行摘要和執行日誌,方便調試。
雲函數 SCF 寫完後,若是想要能經過網絡 http(s) 請求直接訪問,就要爲其添加觸發方式爲 API 網關觸發器。同時強烈建議將鑑權方法置爲 API 網關密鑰對。而後就會在 API Gateway 下自動建立出一個對應的 service API。這一步若是遇到權限問題沒法自動建立 API 的話,也不要着急,能夠直接在 API gateway 的控制檯操做。
參考:API 網關快速入門。
建立 API 時注意將鑑權類型改爲密鑰對。下方有個支持CORS的選項,若是須要跨域訪問就勾上,反之能夠忽略。設置完須要接收的參數後,在下一步的後端配置中選後端類型爲 cloud function 後,選中剛建好的雲函數,就作好了這二者的關聯。
建好 API 後,來到對應服務下的管理 API 標籤就能看到剛建好的 API。在列表的右側有調試入口,千萬不要忘了點進去作下測試。測試完成後,再到服務頁完成發佈,這樣 API 就能夠被訪問到了。
而後,就來到了至關重要但也容易被忽略的訪問控制這步。在前面咱們已經選擇了密鑰對的方式做爲鑑權類型。雖然有密鑰泄露的風險,但對於小網站來講這個驗證也是足夠了,記得保存好密鑰並按期修改就好。
以後的步驟就是建立密鑰對,建立使用計劃綁定密鑰對,再把使用計劃綁定服務或 API。下面直接甩出文檔:使用計劃。使用計劃中除了能夠綁定密鑰對,還能夠進行流量控制,可按需設置。
配置完後端服務後,要解決的就是訪問的問題了。因爲沒錢供服務器,用的是靜態頁面託管的方式建的站。前端直接 ajax 訪問 API 來獲取結果。參考文檔在此:密鑰對認證,如何生成簽名(裏面給出了用不一樣語言生成簽名的例子)。
因爲沒寫前端好多年,對前端的認知還停留在 js 和 jquery 階段,這裏只能給出改好的 jquery 寫法。用的是 crypto-js 加密。
//<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script> function getHeader(){ var nowDate = new Date(); var dateTime = nowDate.toGMTString(); var SecretId = '****'; var SecretKey = '****'; var source = 'your_source'; var auth = "hmac id=\"" + SecretId + "\", algorithm=\"hmac-sha1\", headers=\"x-date source\", signature=\""; var signStr = "x-date: " + dateTime + "\n" + "source: " + source; var sign = CryptoJS.HmacSHA1(signStr, SecretKey) sign = CryptoJS.enc.Base64.stringify(sign) sign = auth + sign + "\"" var header = {"Source": source , "X-Date": dateTime , "Authorization":sign} return header } function getQ(){ $.ajax({ url: "https://xxxx/xx", type: "get", data:{ "op_count" : 1, "op_type" : "+,-", "limit" : 100, "total" : 10 }, dataType: "json", crossDomain: true, headers: getHeader(), success: function (data) { if (data.errorCode < 0){ //deal function error: data.errorMessage return } data= $.parseJSON(data); //show result in page }, error: function(jqXHR, textStatus, errorThrown){ //deal api error } }) }
若是在前面建立 API gateway 的 service 時候沒有指定自定義域名,或是自定義域名和調用頁面的域名不是同一個,就會涉及到跨域的問題。解決跨域問題傳統的方法能夠用 jsonp。但它沒辦法在 request 的 Header 里加參數,也就傳不了鑑權所需的字段。因此這裏只能用 CORS 來解決跨域:
對於服務端,只要前面建 API 的時候勾選了支持 CORS 選項,就會自動開啓,參考 API 控制檯相關問題 。對於客戶端,在 ajax 參數中設置 crossDomain: true
就能夠了。
最後,解決一下頁面上的 bug,測試經過後就大功告成了!給出演示地址:演示,還加上了打印功能,不用再複製粘貼了😀
3 秒你能作什麼?喝一口水,看一封郵件,仍是 —— 部署一個完整的 Serverless 應用?
複製連接至 PC 瀏覽器訪問:https://serverless.cloud.tencent.com/deploy/express
3 秒極速部署,當即體驗史上最快的 Serverless HTTP 實戰開發!
傳送門:
- GitHub: github.com/serverless
- 官網:serverless.com
歡迎訪問:Serverless 中文網,您能夠在 最佳實踐 裏體驗更多關於 Serverless 應用的開發!