如何在AWS Lambda上的Spring Cloud Function中获取请求路径
我能从Lambda Function URL的传入请求中获取主机、查询参数、请求头等信息,但**请求路径(比如xxx.lambda-url.us-west-2.on.aws/example中的/example)**始终缺失。
当前使用的Lambda处理器为:org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest,函数代码如下:
public Function<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> handleRequest() { return value -> { APIGatewayProxyResponseEvent responseEvent = new APIGatewayProxyResponseEvent(); responseEvent.setStatusCode(200); responseEvent.setHeaders(Collections.singletonMap("Content-Type", "text/plain")); responseEvent.setBody(value.toString()); return responseEvent; }; }
我也尝试过使用Message<String>作为输入,但依然无法获取请求路径。
示例响应(路径相关字段缺失):
{version: 2.0,headers: {content-length=5, x-amzn-tls-version=TLSv1.2, x-forwarded-proto=https, postman-token=63fb055b-b7a9-4118-bd65-b3871178feba, x-forwarded-port=443, x-api-token=123456, accept=* /*, x-amzn-tls-cipher-suite=ECDHE-RSA-AES128-GCM-SHA256, x-amzn-trace-id=Root=1-62e0b85d-37132a0f191aa55604dc8ed3, host=xxx.lambda-url.us-west-2.on.aws, content-type=text/plain, cache-control=no-cache, accept-encoding=gzip, deflate, br, user-agent=PostmanRuntime/7.29.2},queryStringParameters: {param1=true},requestContext: {accountId: anonymous,stage: $default,requestId: 82277194-0d8c-4edc-b5b8-7ad35ca62e76,apiId: xxx,},isBase64Encoded: false}
查看Lambda原始传入事件,能看到rawPath和requestContext.http.path字段,但APIGatewayProxyRequestEvent无法映射这些字段:
{ "version": "2.0", "routeKey": "$default", "rawPath": "/testing", "rawQueryString": "hello=true", "headers": { "removed for brevity" }, "queryStringParameters": { "hello": "true" }, "requestContext": { "accountId": "anonymous", "apiId": "xxx", "domainName": "xxx.lambda-url.us-west-2.on.aws", "domainPrefix": "xxx", "http": { "method": "GET", "path": "/testing", "protocol": "HTTP/1.1", "sourceIp": "151.210.174.210", "userAgent": "PostmanRuntime/7.29.2" }, "requestId": "bc27912e-672f-48e3-bf6d-84b28da74431", "routeKey": "$default", "stage": "$default", "time": "27/Jul/2022:20:46:42 +0000", "timeEpoch": 1658954802798 }, "isBase64Encoded": false }
使用的依赖版本:
- aws-lambda-java-core 1.2.1
- aws-lambda-java-events 3.11
- spring-cloud-function-adapter-aws 3.2.6
问题核心是Lambda Function URL的事件格式与APIGatewayProxyRequestEvent不兼容:前者是Lambda原生的Function URL事件结构,而APIGatewayProxyRequestEvent是为API Gateway设计的模型,无法映射Function URL特有的rawPath和requestContext.http字段。可通过以下方式解决:
1. 自定义POJO映射完整事件
创建匹配Function URL事件结构的POJO,直接接收原始事件:
import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import java.util.Map; public class FunctionUrlHandler implements RequestHandler<FunctionUrlRequest, APIGatewayProxyResponseEvent> { @Override public APIGatewayProxyResponseEvent handleRequest(FunctionUrlRequest input, Context context) { // 获取路径信息 String rawPath = input.getRawPath(); String httpPath = input.getRequestContext().getHttp().getPath(); APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); response.setStatusCode(200); response.setHeaders(Map.of("Content-Type", "text/plain")); response.setBody("Raw Path: " + rawPath + "\nHTTP Path: " + httpPath); return response; } // 匹配事件结构的内部类 public static class FunctionUrlRequest { private String version; private String routeKey; private String rawPath; private String rawQueryString; private Map<String, String> headers; private Map<String, String> queryStringParameters; private RequestContext requestContext; private boolean isBase64Encoded; // Getters and Setters public String getRawPath() { return rawPath; } public void setRawPath(String rawPath) { this.rawPath = rawPath; } public RequestContext getRequestContext() { return requestContext; } public void setRequestContext(RequestContext requestContext) { this.requestContext = requestContext; } public static class RequestContext { private String accountId; private String apiId; private Http http; // Getters and Setters public Http getHttp() { return http; } public void setHttp(Http http) { this.http = http; } public static class Http { private String method; private String path; // Getters and Setters public String getPath() { return path; } public void setPath(String path) { this.path = path; } } } // 其他字段的getter/setter省略 } }
2. 使用Map<String, Object>接收原始事件
如果不想定义POJO,可直接用Map<String, Object>接收事件,通过键值对获取路径:
public Function<Map<String, Object>, APIGatewayProxyResponseEvent> handleRequest() { return input -> { // 获取rawPath String rawPath = (String) input.get("rawPath"); // 从requestContext.http中获取path Map<String, Object> requestContext = (Map<String, Object>) input.get("requestContext"); Map<String, Object> http = (Map<String, Object>) requestContext.get("http"); String httpPath = (String) http.get("path"); APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); response.setStatusCode(200); response.setHeaders(Collections.singletonMap("Content-Type", "text/plain")); response.setBody("Raw Path: " + rawPath + "\nHTTP Path: " + httpPath); return response; }; }
3. 升级依赖使用官方适配类
aws-lambda-java-events从3.12.0版本开始,新增了FunctionUrlRequestEvent类,专门用于处理Lambda Function URL事件。升级依赖后直接使用该类:
<!-- Maven依赖示例 --> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-events</artifactId> <version>3.12.0</version> </dependency>
函数代码修改为:
public Function<FunctionUrlRequestEvent, APIGatewayProxyResponseEvent> handleRequest() { return input -> { String rawPath = input.getRawPath(); String httpPath = input.getRequestContext().getHttp().getPath(); APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); response.setStatusCode(200); response.setHeaders(Collections.singletonMap("Content-Type", "text/plain")); response.setBody("Raw Path: " + rawPath + "\nHTTP Path: " + httpPath); return response; }; }
内容的提问来源于stack exchange,提问作者Dale Ogilvie

