aws api网关和;lambda:多端点/函数与单端点
我有一个代理lamba函数的awsapi。我目前使用不同的端点和单独的lambda函数:aws api网关和;lambda:多端点/函数与单端点,api,amazon-web-services,aws-lambda,aws-api-gateway,Api,Amazon Web Services,Aws Lambda,Aws Api Gateway,我有一个代理lamba函数的awsapi。我目前使用不同的端点和单独的lambda函数: api.com/getData --> getData api.com/addData --> addData api.com/signUp --> signUp 管理所有端点和函数的过程变得很麻烦。当我对一个lambda函数使用一个端点来决定根据查询字符串做什么时,有什么缺点吗 api.com/exec&func=getData --> exec --> if(pa
api.com/getData --> getData
api.com/addData --> addData
api.com/signUp --> signUp
管理所有端点和函数的过程变得很麻烦。当我对一个lambda函数使用一个端点来决定根据查询字符串做什么时,有什么缺点吗
api.com/exec&func=getData --> exec --> if(params.func === 'getData') { ... }
将多个方法映射到单个lambda函数是非常有效的,现在很多人都在使用这种方法,而不是为每个离散方法创建api网关资源和lambda函数 <>你可以考虑将所有请求委托给一个函数。请参阅以下有关创建API网关=>Lambda代理集成的文档: 他们的例子在这里很好。请求如下:
POST /testStage/hello/world?name=me HTTP/1.1
Host: gy415nuibc.execute-api.us-east-1.amazonaws.com
Content-Type: application/json
headerName: headerValue
{
"a": 1
}
将向AWS Lambda函数发送以下事件数据:
{
"message": "Hello me!",
"input": {
"resource": "/{proxy+}",
"path": "/hello/world",
"httpMethod": "POST",
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"cache-control": "no-cache",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Content-Type": "application/json",
"headerName": "headerValue",
"Host": "gy415nuibc.execute-api.us-east-1.amazonaws.com",
"Postman-Token": "9f583ef0-ed83-4a38-aef3-eb9ce3f7a57f",
"User-Agent": "PostmanRuntime/2.4.5",
"Via": "1.1 d98420743a69852491bbdea73f7680bd.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "pn-PWIJc6thYnZm5P0NMgOUglL1DYtl0gdeJky8tqsg8iS_sgsKD1A==",
"X-Forwarded-For": "54.240.196.186, 54.182.214.83",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"queryStringParameters": {
"name": "me"
},
"pathParameters": {
"proxy": "hello/world"
},
"stageVariables": {
"stageVariableName": "stageVariableValue"
},
"requestContext": {
"accountId": "12345678912",
"resourceId": "roq9wj",
"stage": "testStage",
"requestId": "deef4878-7910-11e6-8f14-25afc3e9ae33",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"apiKey": null,
"sourceIp": "192.168.196.186",
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "PostmanRuntime/2.4.5",
"user": null
},
"resourcePath": "/{proxy+}",
"httpMethod": "POST",
"apiId": "gy415nuibc"
},
"body": "{\r\n\t\"a\": 1\r\n}",
"isBase64Encoded": false
}
}
现在您可以访问所有的头、url参数、正文等,并且可以使用它们在单个Lambda函数中以不同的方式处理请求(基本上实现您自己的路由)
作为一种观点,我认为这种方法有一些优点和缺点。其中许多取决于您的特定用例:
- 部署:如果每个lambda函数都是离散的,那么您可以独立部署它们,这可能会降低代码更改的风险(微服务策略)。相反地,您可能会发现需要单独部署函数会增加复杂性和负担
- 自我描述:API网关的界面使得查看RESTful端点的布局非常直观——名词和动词一目了然。实现自己的路由可能会以牺牲这种可见性为代价
- Lambda大小和限制:如果代理所有对象,则需要选择一个实例大小、超时等,以适应所有RESTful端点。如果创建离散函数,则可以更仔细地选择最符合特定调用需要的内存占用、超时、死信行为等
/api/{proxy+} -> Lambda
如果您在制作API时使用过类似于您所知道的任何框架,那么
“中间件”“全局异常处理”
“级联路由”
“参数验证”
这是非常关键的。 随着API的增长,几乎不可能使用API网关映射来管理所有路由,API网关也不支持这些功能 此外,在开发或部署时,实际上并没有为每个端点中断lambda 从你的例子来看
api.com/getData --> getData
api.com/addData --> addData
api.com/signUp --> signUp
假设您有数据ORM、用户身份验证逻辑、公共视图文件(如data.erb)。。那你打算怎么分享
你可能会像
api/auth/{+proxy} -> AuthServiceLambda
api/data/{+proxy} -> DataServiceLambda
但不像“每端点”。您可以查阅microservice的概念和有关如何拆分服务的最佳实践
对于那些类似于web框架的功能,我们刚刚为lambda构建了web框架,因为我的公司需要它。我本想在伟大的答案中添加几点注释,但我还没有足够的信誉点,所以我将在这里添加注释 我开始沿着指向一个Lambda函数的多个端点的路径前进,该函数可以通过访问事件的“resource”属性来处理不同的端点。在尝试之后,我现在将它们分为不同的函数,原因是Dave建议plus:
- 我发现当功能分离时,查看日志和监视器更容易
- 作为一个初学者,我一开始没有注意到的一个细微差别是,您可以有一个代码库,并部署与多个Lambda函数完全相同的代码。这使您能够在代码库中获得函数分离和整合方法的好处
- 您可以使用AWS CLI跨多个功能自动化任务,以减少/消除管理单独功能的缺点。例如,我有一个用相同代码更新10个函数的脚本
public class GenericLambda implements RequestHandler<LambdaRequest<?>, LambdaResponse<?>> {
@Override
public LambdaResponse<?> handleRequest(LambdaRequest<?> lambdaRequest, Context context) {
switch (lambdaRequest.getMethod()) {
case WARMUP:
context.getLogger().log("Warmup");
LambdaResponse<String> lambdaResponseWarmup = new LambdaResponse<String>();
lambdaResponseWarmup.setResponseStatus(LambdaResponse.ResponseStatus.IN_PROGRESS);
return lambdaResponseWarmup;
case CREATE:
User user = (User)lambdaRequest.getData();
context.getLogger().log("insert user with name: " + user.getName()); //insert user in db
LambdaResponse<String> lambdaResponseCreate = new LambdaResponse<String>();
lambdaResponseCreate.setResponseStatus(LambdaResponse.ResponseStatus.COMPLETE);
return lambdaResponseCreate;
case READ:
context.getLogger().log("read user with id: " + (Integer)lambdaRequest.getData());
user = new User(); //create user object for test, instead of read from db
user.setName("name");
LambdaResponse<User> lambdaResponseRead = new LambdaResponse<User>();
lambdaResponseRead.setData(user);
lambdaResponseRead.setResponseStatus(LambdaResponse.ResponseStatus.COMPLETE);
return lambdaResponseRead;
default:
LambdaResponse<String> lambdaResponseIgnore = new LambdaResponse<String>();
lambdaResponseIgnore.setResponseStatus(LambdaResponse.ResponseStatus.IGNORED);
return lambdaResponseIgnore;
}
}
}
JUnit测试方法:
@Test
public void GenericLambda() {
GenericLambda handler = new GenericLambda();
Context ctx = createContext();
//test WARMUP
LambdaRequest<String> lambdaRequestWarmup = new LambdaRequest<String>();
lambdaRequestWarmup.setMethod(LambdaRequest.Method.WARMUP);
LambdaResponse<String> lambdaResponseWarmup = (LambdaResponse<String>) handler.handleRequest(lambdaRequestWarmup, ctx);
//test READ user
LambdaRequest<Integer> lambdaRequestRead = new LambdaRequest<Integer>();
lambdaRequestRead.setData(1); //db id
lambdaRequestRead.setMethod(LambdaRequest.Method.READ);
LambdaResponse<User> lambdaResponseRead = (LambdaResponse<User>) handler.handleRequest(lambdaRequestRead, ctx);
}
方法:
private <T> Object convertLambdaRequestData2Object(LambdaRequest<?> lambdaRequest, Class<T> clazz) {
Gson gson = new Gson();
String json = gson.toJson(lambdaRequest.getData());
return gson.fromJson(json, clazz);
}
私有对象ConvertLambDareQuestData2OObject(LambdaRequest LambdaRequest,类clazz){
Gson Gson=新的Gson();
字符串json=gson.toJson(lambdaRequest.getData());
返回gson.fromJson(json,clazz);
}
在我看来,选择单API还是多API是需要考虑以下因素的:
public class User {
private String name;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Test
public void GenericLambda() {
GenericLambda handler = new GenericLambda();
Context ctx = createContext();
//test WARMUP
LambdaRequest<String> lambdaRequestWarmup = new LambdaRequest<String>();
lambdaRequestWarmup.setMethod(LambdaRequest.Method.WARMUP);
LambdaResponse<String> lambdaResponseWarmup = (LambdaResponse<String>) handler.handleRequest(lambdaRequestWarmup, ctx);
//test READ user
LambdaRequest<Integer> lambdaRequestRead = new LambdaRequest<Integer>();
lambdaRequestRead.setData(1); //db id
lambdaRequestRead.setMethod(LambdaRequest.Method.READ);
LambdaResponse<User> lambdaResponseRead = (LambdaResponse<User>) handler.handleRequest(lambdaRequestRead, ctx);
}
YourObject yourObject = (YourObject)convertLambdaRequestData2Object(lambdaRequest, YourObject.class);
private <T> Object convertLambdaRequestData2Object(LambdaRequest<?> lambdaRequest, Class<T> clazz) {
Gson gson = new Gson();
String json = gson.toJson(lambdaRequest.getData());
return gson.fromJson(json, clazz);
}