API网关触发函数计算处理示例教程(runtime=java8)

本文涉及的产品
函数计算FC,每月15万CU 3个月
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: 本示例对API网关触发函数计算的使用步骤进行详细介绍,并以运行环境为Java为例,对API网关传入的请求参数进行解析。 通过示例,您将了解 1. 如何使用API网关触发函数计算; 2. 如何在函数中获取API网关传入函数的参数,并将处理结果返回给API网关(以Java运行环境为例)。

API网关触发java runtime的函数计算处理示例教程

背景信息

函数计算(Function Compute)是一种事件驱动的服务。函数的执行可以由事件驱动,即当某个事件发生时,触发函数的执行。目前函数计算支持API网关作为事件源,简单说来,当有请求到达已经设置函数计算为后端服务的API网关时,API网关会触发函数的执行,函数计算会将执行结果返回给API网关。

本示例对API网关触发函数计算的使用步骤进行详细介绍,并以运行环境为Java为例,对API网关传入的请求参数进行解析。

通过示例,您将了解

  • 如何使用API网关触发函数计算;
  • 如何在函数中获取API网关传入函数的参数,并将处理结果返回给API网关(以Java运行环境为例)。

本示例分为以下三个步骤

  • 明确API网关和函数计算对接的格式要求(一定要以这个格式,否则互相不认识);
  • 创建服务和需要被API网关触发的函数(已有服务和函数,可跳过此步骤);
  • API网关控制台配置函数计算作为API后端服务。

API网关和函数计算对接的格式要求

API网关调用函数服务时,会将API的相关数据包装为一个Map形式传给函数计算服务,函数计算服务处理后,需要按照返回参数的格式返回statusCodeheadersbody等相关数据,API网关再将函数计算返回的内容映射到statusCodeheaderbody等位置返回给客户端。

API网关的传入参数格式

当以函数计算作为API网关的后端服务时,API网关会把请求参数通过一个固定结构传给函数计算的入参event,函数计算通过如下结构去获取需要的参数,然后进行处理,该结构如下:

{
    "path":"api request path",
    "httpMethod":"request method name",
    "headers":{all headers,including system headers},
    "queryParameters":{query parameters},
    "pathParameters":{path parameters},
    "body":"string of request payload",
    "isBase64Encoded":"true|false, indicate if the body is Base64-encode"
}

函数计算的返回参数格式

函数计算需要将输出内容通过如下JSON格式返回给API网关,方便API网关解析。

{
    "isBase64Encoded":true|false,
    "statusCode":httpStatusCode,
    "headers":{response headers},
    "body":"..."
}

创建服务和函数

创建服务和函数部分分为两个步骤,本示例以Java Runtime为例

  • 首先需要编写Java代码对API网关传入的参数进行处理,并返回符合格式要求的结果给API网关
  • 创建服务和函数,函数计算提供给我们两种方式创建服务和函数,本示例对两种创建函数的方式分别进行介绍。(如果已有服务就无需重新创建服务了,新建函数就可以)

    • 一种是通过控制台上传代码包的方式创建函数;
    • 另一种是通过命令行工具fcli创建函数。

温馨提示:这里提供了两种创建函数的方法,您根据个人喜好任选其一即可。

编写函数代码

用户在使用Java编程时,必须要实现一个类,它要实现函数计算预定义的接口,目前有2个预定义的接口可以实现(您任选其一即可):

  • StreamRequestHandler以流的方式接受调用输入(event)和返回执行结果,用户需要从inputStream中读取调用函数时的输入,处理完成后把函数执行结果写入到outputStream中来返回
  • PojoRequestHandler<I, O>通过泛型的方式,用户可以自定义输入和输出的类型,但是它们必须是POJO类型。下面将举例如何使用这个接口
    API网关触发函数计算的场景更适合使用PojoRequestHandler<I, O>接口,但是本文也提供使用以StreamRequestHandler接口实现的方法
使用PojoRequestHandler<I, O>接口(推荐)

本示例演示了在Java Runtime中,通过实现函数计算预定义的接口PojoRequestHandler,对从API网关传入的参数进行处理,并将结果返回给API网关的过程。PojoRequestHandler<I, O>通过泛型的方式接受调用输入和返回执行结果,用户可以自定义输入和输出的类型,但是它们必须是POJO类型。下面将举例如何使用这个接口通过自定义类ApiRequest传入API网关的参数,函数计算获取参数,对参数进行处理,并通过ApiResponse返回函数计算处理结果的过程。
Java Runtime使用请参考Java Runtime

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.PojoRequestHandler;
import java.util.HashMap;
import java.util.Map;

public class ApiTriggerDemo implements PojoRequestHandler<ApiRequest, ApiResponse> {

    public ApiResponse handleRequest(ApiRequest request, Context context) {
        // Get ApiRequest info
        context.getLogger().info(request.toString());
        String path = request.getPath();
        String httpMethod = request.getHttpMethod();
        String body = request.getBody();
        context.getLogger().info("path:" + path);
        context.getLogger().info("httpMethod:" + httpMethod);
        context.getLogger().info("body:" + body);

        // Deal with your own logic here

        // ApiResponse example
        Map headers = new HashMap();
        boolean isBase64Encoded = false;
        int statusCode = 200;
        String returnBody = "";
        return new ApiResponse(headers,isBase64Encoded,statusCode,returnBody);
    }
}

两个pojo类,ApiRequest类和ApiResponse类如下。注意pojo类的set()get()方法注意要写全哈

import java.util.Map;

public class ApiRequest {
    private String path;
    private String httpMethod;
    private Map headers;
    private Map queryParameters;
    private Map pathParameters;
    private String body;
    private boolean isBase64Encoded;

    @Override
    public String toString() {
        return "Request{" +
                "path='" + path + '\'' +
                ", httpMethod='" + httpMethod + '\'' +
                ", headers=" + headers +
                ", queryParameters=" + queryParameters +
                ", pathParameters=" + pathParameters +
                ", body='" + body + '\'' +
                ", isBase64Encoded=" + isBase64Encoded +
                '}';
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getHttpMethod() {
        return httpMethod;
    }

    public void setHttpMethod(String httpMethod) {
        this.httpMethod = httpMethod;
    }

    public Map getHeaders() {
        return headers;
    }

    public void setHeaders(Map headers) {
        this.headers = headers;
    }

    public Map getQueryParameters() {
        return queryParameters;
    }

    public void setQueryParameters(Map queryParameters) {
        this.queryParameters = queryParameters;
    }

    public Map getPathParameters() {
        return pathParameters;
    }

    public void setPathParameters(Map pathParameters) {
        this.pathParameters = pathParameters;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public boolean getIsBase64Encoded() {
        return this.isBase64Encoded;
    }

    public void setIsBase64Encoded(boolean base64Encoded) {
        this.isBase64Encoded = base64Encoded;
    }
}
import java.util.Map;

public class ApiResponse {
    private Map headers;
    private boolean isBase64Encoded;
    private int statusCode;
    private String body;

    public ApiResponse(Map headers, boolean isBase64Encoded, int statusCode, String body) {
        this.headers = headers;
        this.isBase64Encoded = isBase64Encoded;
        this.statusCode = statusCode;
        this.body = body;
    }

    public Map getHeaders() {
        return headers;
    }

    public void setHeaders(Map headers) {
        this.headers = headers;
    }

    public boolean getIsBase64Encoded() {
        return isBase64Encoded;
    }

    public void setIsBase64Encoded(boolean base64Encoded) {
        this.isBase64Encoded = base64Encoded;
    }

    public int getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

pom.xml文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>apiTrigger</groupId>
    <artifactId>apiTrigger</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>com.aliyun.fc.runtime</groupId>
            <artifactId>fc-java-core</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>   
</project>
使用StreamRequestHandler接口

使用StreamRequestHandler接口示例如下,需要将输入的InputStream转换为对应的pojo类,pom文件配置与使用PojoRequestHandler<I, O>接口相同,代码如下

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.StreamRequestHandler;
import com.aliyun.fc.runtime.Context;
import com.google.gson.Gson;
import java.io.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class ApiTriggerDemo2 implements StreamRequestHandler {

    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) {
        try {
            // Convert InputStream to string
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuffer stringBuffer = new StringBuffer();
            String string = "";
            while ((string = bufferedReader.readLine()) != null) {
                stringBuffer.append(string);
            }
            String input = stringBuffer.toString();
            context.getLogger().info("inputStream: " + input);
            Request req = new Gson().fromJson(input, Request.class);
            context.getLogger().info("input req: ");
            context.getLogger().info(req.toString());
            String bodyReq = req.getBody();
            Base64.Decoder decoder = Base64.getDecoder();
            context.getLogger().info("body: " + new String(decoder.decode(bodyReq)));

            // Deal with your own logic here

            // construct response
            Map headers = new HashMap();
            headers.put("x-custom-header", " ");
            boolean isBase64Encoded = false;
            int statusCode = 200;
            Map body = new HashMap();
            Response resp = new Response(headers, isBase64Encoded, statusCode, body);
            String respJson = new Gson().toJson(resp);
            context.getLogger().info("outputStream: " + respJson);
            outputStream.write(respJson.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    class Request {
        private String path;
        private String httpMethod;
        private Map headers;
        private Map queryParameters;
        private Map pathParameters;
        private String body;
        private boolean isBase64Encoded;

        @Override
        public String toString() {
            return "Request{" +
                    "path='" + path + '\'' +
                    ", httpMethod='" + httpMethod + '\'' +
                    ", headers=" + headers +
                    ", queryParameters=" + queryParameters +
                    ", pathParameters=" + pathParameters +
                    ", body='" + body + '\'' +
                    ", isBase64Encoded=" + isBase64Encoded +
                    '}';
        }

        public String getBody() {
            return body;
        }
    }

    // FC need to return the response to API gateway in the following JSON format
    class Response {
        private Map headers;
        private boolean isBase64Encoded;
        private int statusCode;
        private Map body;

        public Response(Map headers, boolean isBase64Encoded, int statusCode, Map body) {
            this.headers = headers;
            this.isBase64Encoded = isBase64Encoded;
            this.statusCode = statusCode;
            this.body = body;
        }
    }
}

创建服务和函数

打成jar包

Java代码需要打成jar包上传到函数计算。如果您使用IntelliJ IDEA集成开发环境,打包方式如下(可参考IDEA导出可执行jar包)

  • File -> Project Structure -> Artifacts -> + -> Jar -> From modules with dependencies -> 选择函数所在的类 -> Apply -> 确定
  • Build -> Build Artifacts -> 找到对应的Aritifacts -> Build
创建服务和函数

函数计算提供两种方式创建服务和函数,使用控制台创建服务和函数和使用命令行工具fcli创建服务和函数,下面对这两种方式分别进行介绍

1.使用控制台创建服务和函数
使用控制台创建服务和函数图文并茂版请参考如何使用控制台,本示例只给出基本操作步骤

  • 创建服务:左侧服务列表 -> + -> 创建服务 -> 填写服务相关内容 -> 确定
  • 创建函数:进入对应服务 -> 左侧函数列表 -> + -> 新建函数 -> 使用空白模板 -> 不创建触发器 -> 输入函数名称 -> 运行环境选择Java8 -> 代码上传方式选择代码包上传 -> 选择刚刚生成的jar包 -> 设置函数入口,入口形式为[package].[class]::[method],例如我打包后的函数入口为ApiTriggerDemo::handleRequest,其他值选择默认即可
    这样函数就创建好啦

2.使用命令行工具fcli创建服务和函数

  • 创建服务: mks fc-demo,即创建服务,服务名称为fc-demo (在创建服务时可以指定log project等信息,具体内容可参考mks
  • 创建函数:
    mkf apiTrigger -t java8 -h ApiTriggerDemo::handleRequest -d fcDemo/out/artifacts/apiTrigger_jar (其中apiTrigger为函数名称,-t为指定运行环境,-h指定函数入口,-d指定代码包,此路径为代码包路径相对于fcli所在位置的路径,具体内容可参考mkf)

创建API

  1. API网关控制台分组管理 -> 创建分组,新建一个API分组(已经有API分组可跳过这步)
  2. API列表 -> 新建API,步骤如图所示
    创建API

API P1
API P2
API P3
API P4

通过API网关触发函数计算可参考以函数计算作为 API 网关后端服务

测试触发器

测试
测试成功后发布API即可

参考文献

以函数计算作为 API 网关后端服务

That's all,enjoy it~
Any question,可留言,或加入函数计算官方客户群(钉钉群号:11721331)

相关文章
|
13天前
|
JSON API 数据格式
Amazon商品详情API,json数据格式示例参考
亚马逊商品详情API接口返回的JSON数据格式通常包含丰富的商品信息,以下是一个简化的JSON数据格式示例参考
|
19天前
|
安全 API UED
WebSocket API 中的 close 事件是如何触发的?
【10月更文挑战第26天】close事件的触发涵盖了从正常的连接关闭到各种异常情况导致的连接中断等多种场景。通过监听close事件,开发人员可以在连接关闭时进行相应的处理,如清理资源、更新界面状态或尝试重新连接等,以确保应用程序的稳定性和良好的用户体验。
|
22天前
|
JSON API 数据格式
店铺所有商品列表接口json数据格式示例(API接口)
当然,以下是一个示例的JSON数据格式,用于表示一个店铺所有商品列表的API接口响应
|
1月前
|
机器学习/深度学习 PyTorch 算法框架/工具
揭秘深度学习中的微调难题:如何运用弹性权重巩固(EWC)策略巧妙应对灾难性遗忘,附带实战代码详解助你轻松掌握技巧
【10月更文挑战第1天】深度学习中,模型微调虽能提升性能,但常导致“灾难性遗忘”,即模型在新任务上训练后遗忘旧知识。本文介绍弹性权重巩固(EWC)方法,通过在损失函数中加入正则项来惩罚对重要参数的更改,从而缓解此问题。提供了一个基于PyTorch的实现示例,展示如何在训练过程中引入EWC损失,适用于终身学习和在线学习等场景。
73 4
揭秘深度学习中的微调难题:如何运用弹性权重巩固(EWC)策略巧妙应对灾难性遗忘,附带实战代码详解助你轻松掌握技巧
|
8天前
|
JSON API 数据格式
携程API接口系列,酒店景点详情请求示例参考
携程API接口系列涵盖了酒店预订、机票预订、旅游度假产品预订、景点门票预订等多个领域,其中酒店和景点详情请求是较为常用的功能。以下提供酒店和景点详情请求的示例参考
|
1月前
|
JSON API 数据安全/隐私保护
拍立淘按图搜索json数据格式示例(API接口)
拍立淘按图搜索API接口为电商平台和购物应用提供了强大的图像搜索功能,能够显著提升用户的购物体验和搜索效率。开发者可以根据自己的需求调用此接口,并处理返回的JSON格式数据来展示推荐商品
|
12天前
|
JSON API 数据安全/隐私保护
拍立淘按图搜索API接口返回数据的JSON格式示例
拍立淘按图搜索API接口允许用户通过上传图片来搜索相似的商品,该接口返回的通常是一个JSON格式的响应,其中包含了与上传图片相似的商品信息。以下是一个基于淘宝平台的拍立淘按图搜索API接口返回数据的JSON格式示例,同时提供对其关键字段的解释
|
1月前
|
API 微服务
Traefik 微服务 API 网关教程(全)
Traefik 微服务 API 网关教程(全)
|
1月前
|
JSON API 数据格式
商品详情数据JSON格式示例参考(api接口)
JSON数据格式的商品详情数据通常包含商品的多个层级信息,以下是一个综合多个来源信息的JSON数据格式的商品详情数据示例参考:
|
1月前
|
存储 前端开发 API
Restful API 设计示例
Restful API 设计示例
32 0

热门文章

最新文章

相关产品

  • 函数计算
  • 下一篇
    无影云桌面