我制作了一个Lambda函数,我想在API网关的帮助下通过URL访问它。
我已经设置好了,我还在API网关中创建了一个application/json
主体映射模板,如下所示:
{
"input": "$input.params('input')",
}
然后我触发HTTP GET请求,看起来像这样:
https://dmquh95ckh.execute-api.eu-west-1.amazonaws.com/prod/OtoTestFunction?input=test
我的Java处理程序类如下:
public class LambdaFunctionHandler implements RequestHandler<String, String> {
@Override
public String handleRequest(String input, Context context) {
context.getLogger().log("Input: " + input);
return "Test completed."+input;
}
}
这是完整的错误信息:
{
"errorMessage": "An error occurred during JSON parsing",
"errorType": "java.lang.RuntimeException",
"stackTrace": [],
"cause": {
"errorMessage": "com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT tokenn at [Source: lambdainternal.util.NativeMemoryAsInputStream@68c4039c; line: 1, column: 1]",
"errorType": "java.io.UncheckedIOException",
"stackTrace": [],
"cause": {
"errorMessage": "Can not deserialize instance of java.lang.String out of START_OBJECT tokenn at [Source: lambdainternal.util.NativeMemoryAsInputStream@68c4039c; line: 1, column: 1]",
"errorType": "com.fasterxml.jackson.databind.JsonMappingException",
"stackTrace": [
"com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)",
"com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:835)",
"com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:59)",
"com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:12)",
"com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1441)",
"com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1047)"
]
}
}
}
当我将输入参数的类型从String更改为Object时,它在所有场景中都对我有效。
public class LambdaFunctionHandler implements RequestHandler<Object, String> {
@Override
public String handleRequest(Object input, Context context) {
String data= input != null ? input.toString() : "{}";
context.getLogger().log("Input: " + data);
return "Test completed."+data;
}
}
**************************添加于2021年3月12日*******************
在完成了几个Lambda实现之后,我意识到输入参数只不过是JSON结构或Map<字符串,对象>代表。对于映射表示,Key是属性的名称,并且该值是(1)如果它是基元值则为String,或者(2)如果它具有多个值则为List,是另一个map<字符串,对象>或者另一个JSON结构。您可以使用恢复JSON表示
if(input instanceof String)
{
String lambdaInputJsonStr = (String)input;
}
else if(input instanceof Map)
{
String lambdaInputJsonStr = gson.toJson((Map)input);
}
这是Lambda反序列化过程中的错误消息。
API网关映射模板正在发送一个JSON对象,但处理程序需要一个String。从API网关发送一个原始字符串,或者更新处理程序以使用与模板输出相对应的POJO。
即
public class MyPojo {
private String input;
public String getInput() { return input; }
public void setInput(String input) { this.input = input; }
}
请参阅:http://docs.aws.amazon.com/lambda/latest/dg/java-programming-model-req-resp.html
我尝试使用Object作为参数类型以及Pojo类,它在某些情况下有效,但当使用API网关URL从浏览器发出请求时,它失败了,并给出了上述错误。花了至少2-3个小时来找出正确的签名,在大多数情况下都有效,如下所示。然而,这是helloworld的例子,您显然会根据自己的需求自定义输入。
public class LambdaFunctionHandler implements RequestHandler<***Map<String,Object>,*** Customer> {
@Override
public Customer handleRequest(***Map<String,Object> input***, Context context) {
}
}
InputStream应该能够处理任何输入。
参考:https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html
InputStream–事件是任何JSON类型。运行时将文档的字节流传递给处理程序而不进行修改。您可以反序列化输入并将输出写入输出流。
public class Handler implements RequestHandler<InputStream, String> {
@Override
public String handleRequest(InputStream event, Context context) {
错误消息试图说"由于input
是一个字符串,我希望它以引用"
开头。但是我看到的是{
;。这就是为什么将input
类型更改为Object
、Map<String,Object>
或MyPojo
会让解析器感到高兴。
如果input
真的应该是String,那么有效负载值本身必须以"
开头。例如String payload = ""string input""
。
正如其他人所提到的,出现此错误是因为JSON请求无法转换为String对象。您可以使用自定义输入参数类来实现处理程序,例如:
public class ZinusoftLambdaHandler implements
RequestHandler<CustomGetEventInput,String> {
public String handleRequest(CustomGetEventInput input, Context context) {
context.getLogger().log("Hello World from ZinusoftLambdaHandler :
"+input.getValue());
return "Response from lambda "+input.getValue();
}
}
CustomGetEventInput类只是一个简单的POJO类。
为了在API中调用POST方法,您需要创建一个Model并将其添加到API定义的MethodRequest部分的请求主体中。模型的json定义需要与CustomGetEventInput类的定义相匹配。
例如
public class CustomEventInput {
private List<Integer> values;
public CustomEventInput() {
}
public CustomEventInput(List<Integer> input) {
values = input;
}
public List<Integer> getValues() {
return values;
}
public void setValues(List<Integer> values) {
this.values = values;
}
}
JSON模型
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "CustomEventInput",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": { "type": "integer" }
}
}
}
对于GET方法,您需要定义一个URL查询字符串,其中包含要传递给lambda函数的参数的名称。
我们可以使用AWS提供的事件类,如APIGatewayProxyRequestEvent、S3Event、SNSEvent等,而不是使用Object类。当您需要查看事件属性,如api查询参数、api方法等时,这将节省大量精力。
您必须包含以下maven依赖项:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>3.11.1</version>
</dependency>