如何序列化DynamoDB Go SDK返回的LastEvaluatedKey作为分页令牌
解决方案
直接使用AWS官方提供的DynamoDB JSON序列化工具即可,无需自行实现AttributeValue的编解码逻辑:
适用SDK版本
- Go SDK v2:使用
github.com/aws/aws-sdk-go-v2/feature/dynamodb/dynamodbjson包 - Go SDK v1:使用
github.com/aws/aws-sdk-go/service/dynamodb/dynamodbjson包
核心工具实现
package something import ( "encoding/base64" "github.com/aws/aws-sdk-go-v2/feature/dynamodb/dynamodbjson" "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) // Encode 把LastEvaluatedKey序列化为URL安全的分页令牌 func Encode(lek map[string]types.AttributeValue) (string, error) { if lek == nil { return "", nil } jsonBytes, err := dynamodbjson.Marshal(lek) if err != nil { return "", err } return base64.URLEncoding.EncodeToString(jsonBytes), nil } // Decode 把客户端传的分页令牌反序列化为ExclusiveStartKey func Decode(token string) (map[string]types.AttributeValue, error) { if token == "" { return nil, nil } jsonBytes, err := base64.URLEncoding.DecodeString(token) if err != nil { return nil, err } var esk map[string]types.AttributeValue err = dynamodbjson.Unmarshal(jsonBytes, &esk) return esk, err }
业务层用法
和你示例中的预期逻辑完全匹配:
func GetDomainObjects(w http.ResponseWriter, req *http.Request) { // ... 解析查询参数、初始化dynamoIn ... esk, err := something.Decode(params.NextToken) if err != nil { http.Error(w, "invalid next_token", http.StatusBadRequest) return } dynamoIn.ExclusiveStartKey = esk dynamoOut, err := db.Query(req.Context(), dynamoIn) if err != nil { // 处理查询错误 return } response := GetDomainObjectsResponse{} _ = attributevalue.UnmarshalListOfMaps(dynamoOut.Items, &response.Items) response.NextToken, _ = something.Encode(dynamoOut.LastEvaluatedKey) // ... 序列化响应返回给客户端 ... }
该方案完全通用,不需要适配不同接口的检索键类型,支持所有DynamoDB合法的属性类型。
可选优化
为防止客户端篡改分页令牌,可以在编解码逻辑中增加HMAC签名校验:
- 序列化时:将生成的JSON字节拼接上服务端私有密钥生成的HMAC签名,再统一做base64编码
- 反序列化时:先解码拆分出签名和JSON内容,校验签名合法后再执行反序列化逻辑
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

