Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
aws api网关和;lambda:多端点/函数与单端点_Api_Amazon Web Services_Aws Lambda_Aws Api Gateway - Fatal编程技术网

aws api网关和;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

我有一个代理lamba函数的awsapi。我目前使用不同的端点和单独的lambda函数:

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端点。如果创建离散函数,则可以更仔细地选择最符合特定调用需要的内存占用、超时、死信行为等

我一直在用Lambda API Gateway构建5~6个微服务,并经历了多次尝试&失败和成功

简而言之,根据我的经验,最好只使用一个APIGateway通配符映射将所有API调用委托给lambda,例如

/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个函数的脚本

据我所知,AWS只允许每个Lambda函数有一个处理程序。这就是为什么我用Java泛型创建了一个小的“路由”机制(用于在编译时进行更强的类型检查)。在下面的示例中,您可以调用多个方法,并通过一个Lambda处理程序将不同的对象类型传递给Lambda和返回:

具有处理程序的Lambda类:

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是需要考虑以下因素的:

  • 安全性:我认为这是拥有单一API结构的最大挑战。对于需求的不同部分,可能有不同的安全配置文件

  • 从业务角度思考微服务模型: 任何API的全部目的都应该是服务于某些请求,因此它必须被很好地理解并易于使用。所以相关的API应该结合起来。例如,如果您有一个移动客户端,它需要从DB中拉入和拉出10个东西,那么将10个端点放在一个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);
    }