编写处理GetObject请求的函数

通过对象FC接入点访问GetObject API时,将触发您所绑定的函数计算服务中的函数,并在函数中配合WriteGetObjectResponse接口实现自定义返回数据和响应标头。

前提条件

已创建对象FC接入点。具体操作,请参见创建对象FC接入点

操作步骤

  1. 编写处理GetObject请求的函数示例。

    Java

    Java SDK要求3.17.2及以上版本。

    import com.aliyun.fc.runtime.Context;
    import com.aliyun.fc.runtime.Credentials;
    import com.aliyun.fc.runtime.StreamRequestHandler;
    import com.aliyun.oss.ClientException;
    import com.aliyun.oss.OSS;
    import com.aliyun.oss.OSSClientBuilder;
    import com.aliyun.oss.OSSException;
    import com.aliyun.oss.model.ObjectMetadata;
    import com.aliyun.oss.model.VoidResult;
    import com.aliyun.oss.model.WriteGetObjectResponseRequest;
    import org.codehaus.jettison.json.JSONException;
    import org.codehaus.jettison.json.JSONObject;
    import javax.imageio.ImageIO;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.*;
    import java.util.Scanner;
    
    public class Example1 implements StreamRequestHandler {
        // Endpoint以华北1(青岛)为例。
        String endpoint = "https://oss-cn-qingdao.aliyuncs.com";
        private static int status = 200;
    
        public static String convertToString(InputStream inputStream) {
            Scanner scanner = new Scanner(inputStream).useDelimiter("\\A");
            return scanner.hasNext() ? scanner.next() : "";
        }
    
        @Override
        public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
            Credentials creds = context.getExecutionCredentials();
            // 从上下文中获取访问密钥。
            OSS ossClient = new OSSClientBuilder().build(endpoint, creds.getAccessKeyId(), creds.getAccessKeySecret(), creds.getSecurityToken());
    
    
            try {
                String result = convertToString(inputStream);
                JSONObject jsonObject = new JSONObject(result);
                String route = jsonObject.getJSONObject("getObjectContext").getString("outputRoute");
                String token = jsonObject.getJSONObject("getObjectContext").getString("outputToken");
                // 通过调用BufferedImage创建200*200像素的对象,并为该对象绘制红色的矩形框。
                // 完成以上调整后,将内容写入WriteGetObjectResponse请求的主体中。
                BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics = image.createGraphics();
                graphics.setColor(Color.RED);
                graphics.fillRect(0, 0, 200, 200);
                graphics.dispose();
    
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ImageIO.write(image, "png", baos);
                WriteGetObjectResponseRequest writeGetObjectResponseRequest = new WriteGetObjectResponseRequest(route, token, status,new ByteArrayInputStream(baos.toByteArray()));
    
                ObjectMetadata metadata = new ObjectMetadata();
                metadata.setContentLength(baos.size());
                writeGetObjectResponseRequest.setMetadata(metadata);
    
                VoidResult voidResult = ossClient.writeGetObjectResponse(writeGetObjectResponseRequest);
                System.out.println("getRequestId:"+voidResult.getRequestId());
                System.out.println("status:"+voidResult.getResponse().getStatusCode());
                System.out.println("Headers:"+voidResult.getResponse().getHeaders().toString());
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message: " + oe.getMessage());
                System.out.println("Error Code:       " + oe.getErrorCode());
                System.out.println("Request ID:      " + oe.getRequestId());
                System.out.println("Host ID:           " + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message: " + ce.getMessage());
            } catch (JSONException e) {
                e.printStackTrace();
            } finally {
                ossClient.shutdown();
            }
        }
    }
    

    Python

    Python SDK要求2.18.3及以上版本。

    # -*- coding: utf-8 -*-
    import io
    from PIL import Image
    import oss2
    import json
    
    # Endpoint以华北1(青岛)为例。
    endpoint = 'http://oss-cn-qingdao.aliyuncs.com'
    fwd_status = '200'
    
    # Fc function entry
    def handler(event, context):
    
        evt = json.loads(event)
        creds = context.credentials
        # do not forget security_token
        auth = oss2.StsAuth(creds.access_key_id, creds.access_key_secret, creds.security_token)
    
        headers = dict()    
    
        event_ctx = evt["getObjectContext"]
        route = event_ctx["outputRoute"]
        token = event_ctx["outputToken"]
        print(evt)
    
        endpoint = route
        service = oss2.Service(auth, endpoint)
        # 通过调用Image方法创建200*200像素的对象,并为该对象绘制红色的矩形框。
        # 完成以上调整后,将内容写入write_get_object_response请求的主体中。
        image = Image.new('RGB', (200, 200), color=(255, 0, 0))
        transformed = io.BytesIO()
        image.save(transformed, "png")
    
        resp = service.write_get_object_response(route, token, fwd_status, transformed.getvalue(), headers)
    
        print('status: {0}'.format(resp.status))
        print(resp.headers)
    
        return 'success'

    Go

    Go SDK要求1.2.2及以上版本。

    package main
    
    import (
      "bytes"
      "context"
      "fmt"
      "github.com/aliyun/aliyun-oss-go-sdk/oss"
      "github.com/aliyun/fc-runtime-go-sdk/fc"
      "github.com/aliyun/fc-runtime-go-sdk/fccontext"
      "image"
      "image/color"
      "image/draw"
      "image/png"
    )
    // 定义GetObjectContext结构体,该结构体包含输出路由(outputRoute)、输出令牌(outputToken)和输入OSS URL(inputOssUrl)。
    type GetObjectContext struct {
      OutputRoute string `json:"outputRoute"`
      OutputToken string `json:"outputToken"`
    }
    // 定义StructEvent结构体,用于接收触发该函数的事件数据。
    type StructEvent struct {
      GetObjectContext GetObjectContext `json:"getObjectContext"`
    }
    // HandleRequest函数主要用于处理计算逻辑。
    func HandleRequest(ctx context.Context, event StructEvent) error {
      fmt.Printf("event:%#v\n", event)
      endpoint := event.GetObjectContext.OutputRoute
      fwdStatus := "200"
      fctx, _ := fccontext.FromContext(ctx)
      // 从上下文中获取访问密钥。
      client, err := oss.New(endpoint, fctx.Credentials.AccessKeyId, fctx.Credentials.AccessKeySecret, oss.SecurityToken(fctx.Credentials.SecurityToken), oss.AuthVersion(oss.AuthV4), oss.Region("cn-qingdao"))
      if err != nil {
        return fmt.Errorf("client new error: %v", err)
      }
      params := map[string]interface{}{}
      params["x-oss-write-get-object-response"] = nil
    
      // 创建200*200像素的图片,并绘制红色的矩形框。
      img := image.NewRGBA(image.Rect(0, 0, 200, 200))
      red := color.RGBA{255, 0, 0, 255}
      draw.Draw(img, img.Bounds(), &image.Uniform{red}, image.Point{}, draw.Src)
    
      // 将图片保存为PNG格式。
      var buf bytes.Buffer
      err = png.Encode(&buf, img)
      if err != nil {
        return fmt.Errorf("png encode error: %v", err)
      }
      reader := bytes.NewReader(buf.Bytes())
      // 通过OSS客户端将转换后的图片以POST请求的形式上传,并设置了特定的HTTP头(例如x-oss-request-route),便于识别和处理特殊的转发请求。
      headers := make(map[string]string)
      headers["x-oss-request-route"] = event.GetObjectContext.OutputRoute
      headers["x-oss-request-token"] = event.GetObjectContext.OutputToken
      headers["x-oss-fwd-status"] = fwdStatus
      resp, err := client.Conn.Do("POST", "", "", params, headers, reader, 0, nil)
      if err != nil {
        return fmt.Errorf("client conn do error: %v", err)
      }
      fmt.Println("status:", resp.StatusCode)
      fmt.Println(resp.Headers)
    
      return nil
    }
    // 启动函数计算入口点,调用fc.Start(HandleRequest)来注册并运行HandleRequest函数,等待并处理来自阿里云函数计算平台的事件触发。
    func main() {
      fc.Start(HandleRequest)
    }
  2. 部署函数。

    Java

    1. 自行打包.jar文件。

    2. 将.jar文件上传至函数计算控制台。

      1. 登录函数计算控制台,单击右上角返回函数计算2.0

      2. 在左侧导航栏,单击服务及函数

      3. 在顶部导航栏,选择华北1(青岛)地域。

      4. 服务列表页面,单击已创建的服务,然后单击已创建的运行环境为Java 11的函数。

      5. 在函数详情页面,选择上传代码 > 上传JAR包

      6. 在弹出的对话框,选择已打包的.jar文件,勾选我想在选中文件后直接部署函数,然后单击保存并部署

    3. 根据函数示例对应修改请求处理程序(函数入口)。

      1. 在函数详情页面,单击函数配置页签。

      2. 环境信息区域,单击编辑

      3. 修改请求处理程序(函数入口)

        当运行环境为Java时,当前值的格式为[package].[class]::[method]。如果当前值为 example.HelloFC::handleRequest,则在函数被触发时,将执行example包中HelloFC类下的handleRequest函数。您需要根据处理GetObject请求的函数示例的实际情况修改当前值,例如com.aliyun.sts.sample.Example1::handleRequest

    Python

    1. 服务列表页面,单击已创建的服务,然后单击已创建的运行环境为Python 3.10的函数。

    2. 在函数详情页面,单击函数代码页签,然后选择Terminal > New Terminal

    3. 在TERMINAL面板,输入以下命令更新OSS Python SDK版本。

      pip install oss2 -t .
    4. 将index.py中的代码示例替换为Python处理GetObject请求的函数示例,然后单击部署函数

    Go

    1. 自行安装Go SDK运行环境。

    2. 编译代码包。具体步骤,请参见编译代码包

      编译过程中,根据需求将main.go编译文件替换为上述步骤提供的需要处理GetObject请求的函数示例。

    3. 将编译生成的二进制文件以ZIP包的形式上传至已创建的运行环境为Go 1的函数,并配置函数处理程序。具体步骤,请参见配置FC函数处理程序

后续步骤

使用对象FC接入点