腾讯云函数下进行Go开发

引言

存在每日必做但不想动手去做的事情,所以只好委托云函数每日自动触发执行

基础

目前scf支持的 Golang 版本为1.8及其以上,对于我这个刷版狂魔,从1.8 升到 1.14.3 这不是问题,舍 GOPATHGo Modules 也不是问题。

在使用 Golang 开发云函数时,需要确保 main 函数位于 package main 中。在 main 函数中,通过使用 github.com/tencentyun/scf-go-lib/cloudfunction 包中的 Start 函数,启动实际处理业务的入口函数。

一个小案例:

package main

import (
    "context"
    "fmt"
    "github.com/tencentyun/scf-go-lib/cloudfunction"
)
// 入口函数
func Run(ctx context.Context) (string, error) {
    fmt.Println("Hello world")
    return "OK", nil
}

//执行入口
func main() {
    cloudfunction.Start(Run)
}

打包编译

Go环境的云函数,仅支持 zip 包上传,这有点气,开发体验感是和 vercel 无法比拟的,作为资深白嫖用户,要不是 vercel 免费用户资源调度受限,并且国内无CDN加速,我可能早就投保 vercel 了。

一直以来我均用我的老旧双核四线程的 Fedora 机器上进行开发,也不觉得不够用。敲击 Linux 命令行也是轻车熟路

# bash
GOOS=linux GOARCH=amd64 go build -o main main.go
zip main.zip main

当然,在windows下进行开发,基本的环境变量配置还是懂的

# cmd
set GOOS=linux
set GOARCH=amd64
go build -o main main.go
# powershell
$env:GOOS=linux
$env:GOARCH=amd64
go build -o main main.go

使用右击压缩工具对输出的二进制文件进行打包,二进制文件需要在 zip 包根目录,后上传到scf中。

入口函数

入口函数是通过 cloudfunction.Start 来启动的函数,官方给的入口函数带参形式如下

func hello()
func hello(ctx context.Context)
func hello(event DefineEvent)
func hello(ctx context.Context, event DefineEvent)

在带有2个入参时,需要确定 context 参数在前,自定义参数在后。

入参

官方提供的 event 只是一种自定义参数的形式,对于需要通过API来进行触发的请求,我们需要借助 github.com/tencentyun/scf-go-lib/events 来帮我们完成,这里正是走自己需要记录的。

events 下包含 events.APIGatewayRequest 该数据结构定义如下

// APIGatewayRequest represents an API gateway request
type APIGatewayRequest struct {
    Headers     map[string]string        `json:"headers"`
    Method      string                   `json:"httpMethod"`
    Path        string                   `json:"path"`
    QueryString APIGatewayQueryString    `json:"queryString"`
    Body        string                   `json:"body"`
    Context     APIGatewayRequestContext `json:"requestContext"`

    // the following fields are ignored
    // HeaderParameters      interface{} `json:"headerParameters"`
    // PathParameters        interface{} `json:"pathParameters"`
    // QueryStringParameters interface{} `json:"queryStringParameters"`
}

可知,当我们入参使用该结构体,即可接收到请求的对于数据。

同样的,events 下包含 events.APIGatewayResponse 该数据结构定义如下

// APIGatewayResponse represents an API gateway response
type APIGatewayResponse struct {
    IsBase64Encoded bool              `json:"isBase64Encoded"`
    StatusCode      int               `json:"statusCode"`
    Headers         map[string]string `json:"headers"`
    Body            string            `json:"body"`
}

返回值返回此数据结构,即可返回一个API响应。

实例:

// Run 执行
func Run(ctx context.Context, event events.APIGatewayRequest) (resp events.APIGatewayResponse, err error) {
    // 返回body中的内容
    var body = struct {
        Code    int         `json:"code"`
        Message interface{} `json:"message"`
    }{}

    //整体API响应 保证CORS跨域
    resp = events.APIGatewayResponse{
        IsBase64Encoded: false,
        Headers:         map[string]string{"Content-Type": "application/json", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "*"},
    }

    // 检测 post/get 等请求参数 tel 是否缺失 (是一个二维数组 即 key:[value...])
    // 检测 headers 参数 SecretKey 是否缺失
    // 检测 body 传递的 json数据 是否缺失
    if event.QueryString["tel"] != nil && event.Headers["SecretKey"] != "" && event.Body != "" {
        body.Code = 200
        body.Message = "参数齐全!"
        ret, _ := json.Marshal(body)
        resp.Body = string(ret)
        resp.StatusCode = body.Code
        return //返回
    }

    body.Code = 400
    body.Message = "error:参数缺失"
    ret, _ := json.Marshal(body)
    resp.Body = string(ret)
    resp.StatusCode = body.Code
    return
}

func main() {
    cloudfunction.Start(Run)
}

需要说明的是 post/get 参数在 APIGatewayRequest 中均通过 QueryString 获取。若传参 json 数据,则通过 body 接收。

前端的请求可能如此来传递 json数据

//header头部设置
let header = {
    'Content-Type': 'application/json',
    'SecretKey': 'Cloud_Dev_Bad',
}

let data = {
    bj: "北京",
    sh: "上海",
}

//查询是否存在该手机记录
await this.$api.post('https://API_ADDRESS/release/api?tel=1380000000', data, {
    headers: header
}).then(response => {
    //成功
}).catch(error => {
    //失败
})

暂时写到这里吧!