When a client calls GetObject through an Object FC Access Point, OSS triggers the bound Function Compute function before returning the response. Inside the function, call WriteGetObjectResponse to send custom data and response headers back to the caller.
Prerequisites
Before you begin, ensure that you have:
An Object FC Access Point. For instructions, see Create Object FC Access Points
How the function works
When your function is triggered, it receives an event that includes a getObjectContext object with two fields:
| Field | Description |
|---|---|
outputRoute | The endpoint where you send the WriteGetObjectResponse request |
outputToken | A single-use token that authorizes the response |
Step 1: Write the function
The examples below generate a 200x200 red PNG image as the response body. In production, retrieve the original object using outputRoute and process it before writing the response.
Java
Requires OSS SDK for Java 3.17.2 or later.
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 for the China (Qingdao) region
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 {
// Get temporary credentials from the function execution context
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);
// outputRoute: where to send the WriteGetObjectResponse request
// outputToken: single-use token that authorizes the response
String route = jsonObject.getJSONObject("getObjectContext").getString("outputRoute");
String token = jsonObject.getJSONObject("getObjectContext").getString("outputToken");
// Build a 200x200 red PNG image as the response body
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
Requires OSS SDK for Python 2.18.3 or later.
# -*- coding: utf-8 -*-
import io
from PIL import Image
import oss2
import json
# Endpoint for the China (Qingdao) region
endpoint = 'http://oss-cn-qingdao.aliyuncs.com'
fwd_status = '200'
# Function entry point
def handler(event, context):
evt = json.loads(event)
# Get temporary credentials from the function execution context.
# The security token is required for STS-based authentication.
creds = context.credentials
auth = oss2.StsAuth(creds.access_key_id, creds.access_key_secret, creds.security_token)
headers = dict()
# outputRoute: where to send the WriteGetObjectResponse request
# outputToken: single-use token that authorizes the response
event_ctx = evt["getObjectContext"]
route = event_ctx["outputRoute"]
token = event_ctx["outputToken"]
print(evt)
endpoint = route
service = oss2.Service(auth, endpoint)
# Build a 200x200 red PNG image as the response body
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
Requires OSS SDK for Go 1.2.2 or later.
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 holds the routing and authorization fields from the trigger event.
// outputRoute: where to send the WriteGetObjectResponse request
// outputToken: single-use token that authorizes the response
type GetObjectContext struct {
OutputRoute string `json:"outputRoute"`
OutputToken string `json:"outputToken"`
}
// StructEvent is the top-level event structure received when the function is triggered.
type StructEvent struct {
GetObjectContext GetObjectContext `json:"getObjectContext"`
}
// HandleRequest processes the GetObject interception and sends a custom response.
func HandleRequest(ctx context.Context, event StructEvent) error {
fmt.Printf("event:%#v\n", event)
endpoint := event.GetObjectContext.OutputRoute
fwdStatus := "200"
// Get temporary credentials from the function execution context
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
// Build a 200x200 red PNG image as the response body
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)
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())
// Send a POST request with the required routing headers to deliver the response
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
}
// Start the function runtime and register the handler
func main() {
fc.Start(HandleRequest)
}Step 2: Deploy the function
Java
Decompress the .jar file.
Upload the .jar file to the Function Compute console.
Log on to the Function Compute console. Click Back to Function Compute 2.0 in the upper-right corner.
In the left-side navigation pane, click Services & Functions.
In the top navigation bar, select China (Qingdao).
On the Services page, click the service you created, and then click the function whose runtime is Java 11.
On the function details page, choose Upload Code > Upload JAR Package.
In the dialog box, select the .jar file, select Deploy the function after the files are selected., and then click Save and Deploy.
Update the function handler.
On the function details page, click the Configurations tab.
In the Environment Information section, click Edit.
Update the Handler parameter to match your class and method. The handler format is
[package].[class]::[method]. For example, if your class isExample1in thecom.aliyun.sts.samplepackage, set the handler tocom.aliyun.sts.sample.Example1::handleRequest.
Python
On the Services page, click the service you created, and then click the function whose runtime is Python 3.10.
On the function details page, click the Code tab, and then choose Terminal > New Terminal.
In the TERMINAL panel, install the required SDK version:
pip install oss2 -t .Replace the sample code in
index.pywith your function code, and then click Deploy.
Go
Install the OSS SDK for Go runtime environment.
Compile the code package. For instructions, see Compile and package code on Linux or macOS. Replace
main.gowith your function code before compiling.Upload the compiled binary as a ZIP package to the function in the Go 1 runtime environment, and configure the handler. For instructions, see Configure Function Compute handlers.