英文:
curl request to AWS lambda function receives no json
问题
我直接从Lambda教程的Go部分复制了代码:
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/aws/aws-lambda-go/lambda"
)
type MyEvent struct {
Name string `json:"name"`
Age int `json:"age"`
}
type MyResponse struct {
Message string `json:"Answer"`
}
func HandleLambdaEvent(ctx context.Context, event MyEvent) (MyResponse, error) {
// event
eventJson, _ := json.MarshalIndent(event, "", " ")
log.Printf("EVENT: %s", eventJson)
return MyResponse{Message: fmt.Sprintf("%s is %d years old!", event.Name, event.Age)}, nil
}
func main() {
lambda.Start(HandleLambdaEvent)
}
我创建了一个.zip文件,一个角色,并将该角色附加到Lambda函数上。
我可以成功地使用aws lambda调用该函数:
# aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"name": "Kevin", "age":62}' output.txt
# cat output.txt
{"Answer":"Kevin is 62 years old!"}
我创建了一个函数URL,并可以通过awscurl(或curl)调用它:
# curl -X POST https://XXXXXXXXXX.lambda-url.us-east-1.on.aws/ \
-H 'Content-type: application/json' \
--user AWS_ID:AWS_KEY \
--aws-sigv4 "aws:amz:us-east-1:lambda \
-d '{"Name": "Kevin", "Age": 62}'
但是JSON数据没有传递给函数(从日志中验证),因此没有被my-function处理:
{"Answer":" is 0 years old!"}
我已经尝试过调整lambda:InvokeFunctionURL
,但没有任何改变。
更新:我对HandleLambdaRequest
函数进行了相当大的更改,如下所示:
func HandleLambdaEvent(ctx context.Context, request map[string]interface{}) (MyResponse, error) {
// event
jsonStr, err := json.Marshal(request)
if err != nil {
return MyResponse{Message: "can't unmarshal request"}, nil
}
var event Event
if err = json.Unmarshal(jsonStr, &event); err != nil {
return MyResponse{Message: err.Error()}, nil
}
if event.Name == "" {
var apigate events.APIGatewayV2HTTPRequest
if err = json.Unmarshal(jsonStr, &apigate); err != nil {
return MyResponse{Message: "can't get event or request"}, nil
}
body := []byte(apigate.Body)
if err = json.Unmarshal(body, &event); err != nil {
return MyResponse{Message: "can't unmarshal api.Body"}, nil
}
return MyResponse{Message: fmt.Sprintf("url %s:%d", event.Name, event.Age)}, nil
}
return MyResponse{Message: fmt.Sprintf("invoke %s:%d", event.Name, event.Age)}, nil
}
以上是你提供的代码的翻译。
英文:
I have code copied directly from the go section of the lambda tutorial
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/aws/aws-lambda-go/lambda"
)
type MyEvent struct {
Name string `json:"name"`
Age int `json:"age"`
}
type MyResponse struct {
Message string `json:"Answer"`
}
func HandleLambdaEvent(ctx context.Context, event MyEvent) (MyResponse, error) {
// event
eventJson, _ := json.MarshalIndent(event, "", " ")
log.Printf("EVENT: %s", eventJson)
return MyResponse{Message: fmt.Sprintf("%s is %d years old!", event.Name, event.Age)}, nil
}
func main() {
lambda.Start(HandleLambdaEvent)
}
I have created a .zip file, a role, attached that role and created the function on lambda.
I can invoke the function with aws lambda successfully
# aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"name": "Kevin", "age":62}' output.txt
# cat output.txt
{"Answer":"Kevin is 62 years old!"}
I created a function URL and can call it via awscurl (or curl)
# curl -X POST https://XXXXXXXXXX.lambda-url.us-east-1.on.aws/ \
-H 'Content-type: application/json' \
--user AWS_ID:AWS_KEY \
--aws-sigv4 "aws:amz:us-east-1:lambda \
-d '{"Name": "Kevin", "Age": 62}'
But the json doesn't go to the function (verified from the logs) and so isn't processed by my-function
{"Answer":" is 0 years old!"}
I have futzed with lambda:InvokeFunctionURL
but this didn't make any difference
Update: I changed my HandleLambdaRequest
function quite a bit, see below
func HandleLambdaEvent(ctx context.Context, request map[string]interface{}) (MyResponse, error) {
// event
jsonStr, err := json.Marshal(request)
if err != nil {
return MyResponse{Message: "can't unmarshal request"}, nil
}
var event Event
if err = json.Unmarshal(jsonStr, &event); err != nil {
return MyResponse{Message: err.Error()}, nil
}
if event.Name == "" {
var apigate events.APIGatewayV2HTTPRequest
if err = json.Unmarshal(jsonStr, &apigate); err != nil {
return MyResponse{Message: "can't get event or request"}, nil
}
body := []byte(apigate.Body)
if err = json.Unmarshal(body, &event); err != nil {
return MyResponse{Message: "can't unmarshal api.Body"}, nil
}
return MyResponse{Message: fmt.Sprintf("url %s:%d", event.Name, event.Age)}, nil
}
return MyResponse{Message: fmt.Sprintf("invoke %s:%d", event.Name, event.Age)}, nil
}
答案1
得分: 2
Lambda在通过函数URL调用函数时会以不同的方式处理您的请求!对于不熟悉Amazon API Gateway服务中Lambda集成的人来说,这并不直观,希望文档中能更清楚地说明这一点。这里是请求和响应负载结构。在您的情况下,POST负载映射到event.Body
,您需要像这样在"MyEvent"结构中定义"body",
type MyEvent struct {
...
Body string `json:body`
}
希望对您有所帮助。
英文:
Lambda handles your request differently when you invoke the function through a function URL! This is not very intuitive, especially for people who are not familiar with the lambda integration in the Amazon API Gateway service, and I hope they make this more clear in the documentation. Here is the request and response payload structures. In your case, the POST payload is mapped to event.Body
, and you need to define "body" in the "MyEvent" struct like this,
type MyEvent struct {
...
Body string `json:body`
}
Hope this helps.
答案2
得分: 1
MyEvent
与您的Lambda实际接收到的有效负载不匹配。当通过函数URL调用时,您的Lambda会接收到一个具有API Gateway请求形状的事件。
github.com/aws/aws-lambda-go包含各种Lambda调用事件的请求和响应类型。APIGatewayV2HTTPRequest是您要查找的类型。您的POST有效负载位于Body
中。
type APIGatewayV2HTTPRequest struct {
Version string `json:"version"`
RouteKey string `json:"routeKey"`
RawPath string `json:"rawPath"`
RawQueryString string `json:"rawQueryString"`
Cookies []string `json:"cookies,omitempty"`
Headers map[string]string `json:"headers"`
QueryStringParameters map[string]string `json:"queryStringParameters,omitempty"`
PathParameters map[string]string `json:"pathParameters,omitempty"`
RequestContext APIGatewayV2HTTPRequestContext `json:"requestContext"`
StageVariables map[string]string `json:"stageVariables,omitempty"`
Body string `json:"body,omitempty"`
IsBase64Encoded bool `json:"isBase64Encoded"`
}
英文:
MyEvent
does not match the payload your Lambda is actually receiving. When invoked via a Function URL, your Lambda receives an event with the shape of an API Gateway request.
The github.com/aws/aws-lambda-go package contains the request and response types for the various Lambda invoke events. APIGatewayV2HTTPRequest is the one you're looking for. Your POST payload is in Body
.
type APIGatewayV2HTTPRequest struct {
Version string `json:"version"`
RouteKey string `json:"routeKey"`
RawPath string `json:"rawPath"`
RawQueryString string `json:"rawQueryString"`
Cookies []string `json:"cookies,omitempty"`
Headers map[string]string `json:"headers"`
QueryStringParameters map[string]string `json:"queryStringParameters,omitempty"`
PathParameters map[string]string `json:"pathParameters,omitempty"`
RequestContext APIGatewayV2HTTPRequestContext `json:"requestContext"`
StageVariables map[string]string `json:"stageVariables,omitempty"`
Body string `json:"body,omitempty"`
IsBase64Encoded bool `json:"isBase64Encoded"`
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论