

# S3 Object Lambda アクセスポイントの Lambda 関数の記述
<a name="olap-writing-lambda"></a>

**注記**  
2025 年 11 月 7 日現在、S3 Object Lambda は、現在サービスを使用している既存のお客様、および一部の AWS パートナーネットワーク (APN) パートナーのみが利用できます。S3 Object Lambda と同様の機能の詳細については、「[Amazon S3 Object Lambda availability change](https://docs.aws.amazon.com/AmazonS3/latest/userguide/amazons3-ol-change.html)」を参照してください。

このセクションでは、Amazon S3 Object Lambda アクセスポイントで使用するための AWS Lambda 関数を記述する方法について詳述します。

S3 Object Lambda の一部のタスクにおける完全なエンドツーエンド手順については、以下を参照してください。
+ [チュートリアル: S3 Object Lambda を使用したアプリケーションのデータの変換](tutorial-s3-object-lambda-uppercase.md)
+ [チュートリアル: S3 Object Lambda と Amazon Comprehend を使用した PII データの検出と編集](tutorial-s3-object-lambda-redact-pii.md)
+ [チュートリアル: S3 Object Lambda を使用して、取得時に画像に動的に透かしを入れる](https://aws.amazon.com/getting-started/hands-on/amazon-s3-object-lambda-to-dynamically-watermark-images/?ref=docs_gateway/amazons3/olap-writing-lambda.html)

**Topics**
+ [Lambdaでの `GetObject` リクエストの処理](#olap-getobject-response)
+ [Lambdaでの `HeadObject` リクエストの処理](#olap-headobject)
+ [Lambda での `ListObjects` リクエストの使用](#olap-listobjects)
+ [Lambda での `ListObjectsV2` リクエストの使用](#olap-listobjectsv2)
+ [イベントコンテキストの形式と使用法](olap-event-context.md)
+ [Range および partNumber ヘッダーの操作](range-get-olap.md)

## Lambdaでの `GetObject` リクエストの処理
<a name="olap-getobject-response"></a>

このセクションでは、Object Lambda アクセスポイントが `GetObject` 用に Lambda 関数を呼び出すように設定されていることを前提としています。S3 Object Lambda には、Amazon S3 API オペレーション、`WriteGetObjectResponse` が含まれています。これにより、Lambda 関数は、カスタマイズされたデータとレスポンスヘッダーを `GetObject` 発信者に提供できるようになります。

`WriteGetObjectResponse` は、処理のニーズに基づいて、ステータスコード、レスポンスヘッダー、レスポンス本文を広範囲に制御できます。`WriteGetObjectResponse` を使用すると、変換されたオブジェクト全体、変換されたオブジェクトの一部、またはアプリケーションのコンテキストに基づくその他のレスポンスに対して応答することができます。次のセクションでは、`WriteGetObjectResponse` API オペレーションを使用した一意の例を示します。
+ **例 1:** HTTP ステータスコード 403 (Forbidden) で応答します。
+ **例 2:** 変換された画像で応答する
+ **例 3:** 圧縮されたコンテンツをストリーミングする

**例 1: HTTP ステータスコード 403 (Forbidden) で応答します。**

`WriteGetObjectResponse` を使用して、オブジェクトの内容に基づいて HTTP ステータスコード 403 (Forbidden) で応答できます。

------
#### [ Java ]



```
package com.amazon.s3.objectlambda;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.S3ObjectLambdaEvent;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.WriteGetObjectResponseRequest;

import java.io.ByteArrayInputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Example1 {

    public void handleRequest(S3ObjectLambdaEvent event, Context context) throws Exception {
        S3Client s3Client = S3Client.builder().build();

        // Check to see if the request contains all of the necessary information.
        // If it does not, send a 4XX response and a custom error code and message.
        // Otherwise, retrieve the object from S3 and stream it
        // to the client unchanged.
        var tokenIsNotPresent = !event.getUserRequest().getHeaders().containsKey("requiredToken");
        if (tokenIsNotPresent) {
            s3Client.writeGetObjectResponse(WriteGetObjectResponseRequest.builder()
                    .requestRoute(event.outputRoute())
                    .requestToken(event.outputToken())
                    .statusCode(403)
                    .contentLength(0L)
                    .errorCode("MissingRequiredToken")
                    .errorMessage("The required token was not present in the request.")
                    .build(),
                    RequestBody.fromInputStream(new ByteArrayInputStream(new byte[0]), 0L));
            return;
        }

        // Prepare the presigned URL for use and make the request to S3.
        HttpClient httpClient = HttpClient.newBuilder().build();
        var presignedResponse = httpClient.send(
                HttpRequest.newBuilder(new URI(event.inputS3Url())).GET().build(),
                HttpResponse.BodyHandlers.ofInputStream());

        // Stream the original bytes back to the caller.
        s3Client.writeGetObjectResponse(WriteGetObjectResponseRequest.builder()
                .requestRoute(event.outputRoute())
                .requestToken(event.outputToken())
                .build(),
                RequestBody.fromInputStream(presignedResponse.body(),
                    presignedResponse.headers().firstValueAsLong("content-length").orElse(-1L)));
    }
}
```

------
#### [ Python ]



```
import boto3
import requests 

def handler(event, context):
    s3 = boto3.client('s3')

    """
    Retrieve the operation context object from the event. This object indicates where the WriteGetObjectResponse request
    should be delivered and contains a presigned URL in 'inputS3Url' where we can download the requested object from.
    The 'userRequest' object has information related to the user who made this 'GetObject' request to 
    S3 Object Lambda.
    """
    get_context = event["getObjectContext"]
    user_request_headers = event["userRequest"]["headers"]

    route = get_context["outputRoute"]
    token = get_context["outputToken"]
    s3_url = get_context["inputS3Url"]

    # Check for the presence of a 'CustomHeader' header and deny or allow based on that header.
    is_token_present = "SuperSecretToken" in user_request_headers

    if is_token_present:
        # If the user presented our custom 'SuperSecretToken' header, we send the requested object back to the user.
        response = requests.get(s3_url)
        s3.write_get_object_response(RequestRoute=route, RequestToken=token, Body=response.content)
    else:
        # If the token is not present, we send an error back to the user. 
        s3.write_get_object_response(RequestRoute=route, RequestToken=token, StatusCode=403,
        ErrorCode="NoSuperSecretTokenFound", ErrorMessage="The request was not secret enough.")

    # Gracefully exit the Lambda function.
    return { 'status_code': 200 }
```

------
#### [ Node.js ]



```
const { S3 } = require('aws-sdk');
const axios = require('axios').default;

exports.handler = async (event) => {
    const s3 = new S3();

    // Retrieve the operation context object from the event. This object indicates where the WriteGetObjectResponse request
    // should be delivered and contains a presigned URL in 'inputS3Url' where we can download the requested object from.
    // The 'userRequest' object has information related to the user who made this 'GetObject' request to S3 Object Lambda.
    const { userRequest, getObjectContext } = event;
    const { outputRoute, outputToken, inputS3Url } = getObjectContext;

    // Check for the presence of a 'CustomHeader' header and deny or allow based on that header.
    const isTokenPresent = Object
        .keys(userRequest.headers)
        .includes("SuperSecretToken");

    if (!isTokenPresent) {
        // If the token is not present, we send an error back to the user. The 'await' in front of the request
        // indicates that we want to wait for this request to finish sending before moving on. 
        await s3.writeGetObjectResponse({
            RequestRoute: outputRoute,
            RequestToken: outputToken,
            StatusCode: 403,
            ErrorCode: "NoSuperSecretTokenFound",
            ErrorMessage: "The request was not secret enough.",
        }).promise();
    } else {
        // If the user presented our custom 'SuperSecretToken' header, we send the requested object back to the user.
        // Again, note the presence of 'await'.
        const presignedResponse = await axios.get(inputS3Url);
        await s3.writeGetObjectResponse({
            RequestRoute: outputRoute,
            RequestToken: outputToken,
            Body: presignedResponse.data,
        }).promise();
    }

    // Gracefully exit the Lambda function.
    return { statusCode: 200 };
}
```

------

**例 2: 変換された画像で応答する**

画像変換を実行する場合、ソースオブジェクトの処理を開始する前に、ソースオブジェクトのすべてのバイトが必要になる可能性があります。この場合、`WriteGetObjectResponse` リクエストは、オブジェクト全体を 1 回の呼び出しでリクエスト元のアプリケーションに返します。

------
#### [ Java ]



```
package com.amazon.s3.objectlambda;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.S3ObjectLambdaEvent;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.WriteGetObjectResponseRequest;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.Image;
import java.io.ByteArrayOutputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Example2V2 {

    private static final int HEIGHT = 250;
    private static final int WIDTH = 250;

    public void handleRequest(S3ObjectLambdaEvent event, Context context) throws Exception {
        S3Client s3Client = S3Client.builder().build();
        HttpClient httpClient = HttpClient.newBuilder().build();

        // Prepare the presigned URL for use and make the request to S3.
        var presignedResponse = httpClient.send(
                HttpRequest.newBuilder(new URI(event.inputS3Url())).GET().build(),
                HttpResponse.BodyHandlers.ofInputStream());

        // The entire image is loaded into memory here so that we can resize it.
        // Once the resizing is completed, we write the bytes into the body
        // of the WriteGetObjectResponse request.
        var originalImage = ImageIO.read(presignedResponse.body());
        var resizingImage = originalImage.getScaledInstance(WIDTH, HEIGHT, Image.SCALE_DEFAULT);
        var resizedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        resizedImage.createGraphics().drawImage(resizingImage, 0, 0, WIDTH, HEIGHT, null);

        var baos = new ByteArrayOutputStream();
        ImageIO.write(resizedImage, "png", baos);

        // Stream the bytes back to the caller.
        s3Client.writeGetObjectResponse(WriteGetObjectResponseRequest.builder()
                .requestRoute(event.outputRoute())
                .requestToken(event.outputToken())
                .build(), RequestBody.fromBytes(baos.toByteArray()));
    }
}
```

------
#### [ Python ]



```
import boto3
import requests 
import io
from PIL import Image

def handler(event, context):
    """
    Retrieve the operation context object from the event. This object indicates where the WriteGetObjectResponse request
    should be delivered and has a presigned URL in 'inputS3Url' where we can download the requested object from.
    The 'userRequest' object has information related to the user who made this 'GetObject' request to 
    S3 Object Lambda.
    """
    get_context = event["getObjectContext"]
    route = get_context["outputRoute"]
    token = get_context["outputToken"]
    s3_url = get_context["inputS3Url"]

    """
    In this case, we're resizing .png images that are stored in S3 and are accessible through the presigned URL
    'inputS3Url'.
    """
    image_request = requests.get(s3_url)
    image = Image.open(io.BytesIO(image_request.content))
    image.thumbnail((256,256), Image.ANTIALIAS)

    transformed = io.BytesIO()
    image.save(transformed, "png")

    # Send the resized image back to the client.
    s3 = boto3.client('s3')
    s3.write_get_object_response(Body=transformed.getvalue(), RequestRoute=route, RequestToken=token)

    # Gracefully exit the Lambda function.
    return { 'status_code': 200 }
```

------
#### [ Node.js ]



```
const { S3 } = require('aws-sdk');
const axios = require('axios').default;
const sharp = require('sharp');

exports.handler = async (event) => {
    const s3 = new S3();

    // Retrieve the operation context object from the event. This object indicates where the WriteGetObjectResponse request
    // should be delivered and has a presigned URL in 'inputS3Url' where we can download the requested object from.
    const { getObjectContext } = event;
    const { outputRoute, outputToken, inputS3Url } = getObjectContext;

    // In this case, we're resizing .png images that are stored in S3 and are accessible through the presigned URL
    // 'inputS3Url'.
    const { data } = await axios.get(inputS3Url, { responseType: 'arraybuffer' });

    // Resize the image.
    const resized = await sharp(data)
        .resize({ width: 256, height: 256 })
        .toBuffer();

    // Send the resized image back to the client.
    await s3.writeGetObjectResponse({
        RequestRoute: outputRoute,
        RequestToken: outputToken,
        Body: resized,
    }).promise();

    // Gracefully exit the Lambda function.
    return { statusCode: 200 };
}
```

------

**例 3: 圧縮されたコンテンツをストリーミングする**

オブジェクトを圧縮すると、圧縮データは増分的に生成されます。したがって、準備ができたらすぐに圧縮されたデータを返すために、`WriteGetObjectResponse` リクエストを使用できます。この例で示すように、完了した変換の長さを知る必要はありません。

------
#### [ Java ]



```
package com.amazon.s3.objectlambda;

import com.amazonaws.services.lambda.runtime.events.S3ObjectLambdaEvent;
import com.amazonaws.services.lambda.runtime.Context;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.WriteGetObjectResponseRequest;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Example3 {

    public void handleRequest(S3ObjectLambdaEvent event, Context context) throws Exception {
        S3Client s3Client = S3Client.builder().build();
        HttpClient httpClient = HttpClient.newBuilder().build();

        // Request the original object from S3.
        var presignedResponse = httpClient.send(
                HttpRequest.newBuilder(new URI(event.inputS3Url())).GET().build(),
                HttpResponse.BodyHandlers.ofInputStream());

        // Consume the incoming response body from the presigned request,
        // apply our transformation on that data, and emit the transformed bytes
        // into the body of the WriteGetObjectResponse request as soon as they're ready.
        // This example compresses the data from S3, but any processing pertinent
        // to your application can be performed here.
        var bodyStream = new GZIPCompressingInputStream(presignedResponse.body());

        // Stream the bytes back to the caller.
        s3Client.writeGetObjectResponse(WriteGetObjectResponseRequest.builder()
                .requestRoute(event.outputRoute())
                .requestToken(event.outputToken())
                .build(),
                RequestBody.fromInputStream(bodyStream,
                    presignedResponse.headers().firstValueAsLong("content-length").orElse(-1L)));
    }
}
```

------
#### [ Python ]



```
import boto3
import requests
import zlib
from botocore.config import Config


"""
A helper class to work with content iterators. Takes an interator and compresses the bytes that come from it. It
implements 'read' and '__iter__' so that the SDK can stream the response. 
"""
class Compress:
    def __init__(self, content_iter):
        self.content = content_iter
        self.compressed_obj = zlib.compressobj()

    def read(self, _size):
        for data in self.__iter__()
            return data

    def __iter__(self):
        while True:
            data = next(self.content)
            chunk = self.compressed_obj.compress(data)
            if not chunk:
                break

            yield chunk

        yield self.compressed_obj.flush()


def handler(event, context):
    """
    Setting the 'payload_signing_enabled' property to False allows us to send a streamed response back to the client.
    in this scenario, a streamed response means that the bytes are not buffered into memory as we're compressing them,
    but instead are sent straight to the user.
    """
    my_config = Config(
        region_name='eu-west-1',
        signature_version='s3v4',
        s3={
            "payload_signing_enabled": False
        }
    )
    s3 = boto3.client('s3', config=my_config)

    """
    Retrieve the operation context object from the event. This object indicates where the WriteGetObjectResponse request
    should be delivered and has a presigned URL in 'inputS3Url' where we can download the requested object from.
    The 'userRequest' object has information related to the user who made this 'GetObject' request to S3 Object Lambda.
    """
    get_context = event["getObjectContext"]
    route = get_context["outputRoute"]
    token = get_context["outputToken"]
    s3_url = get_context["inputS3Url"]

    # Compress the 'get' request stream.
    with requests.get(s3_url, stream=True) as r:
        compressed = Compress(r.iter_content())

        # Send the stream back to the client.
        s3.write_get_object_response(Body=compressed, RequestRoute=route, RequestToken=token, ContentType="text/plain",
                                     ContentEncoding="gzip")

    # Gracefully exit the Lambda function.
    return {'status_code': 200}
```

------
#### [ Node.js ]



```
const { S3 } = require('aws-sdk');
const axios = require('axios').default;
const zlib = require('zlib');

exports.handler = async (event) => {
    const s3 = new S3();

    // Retrieve the operation context object from the event. This object indicates where the WriteGetObjectResponse request
    // should be delivered and has a presigned URL in 'inputS3Url' where we can download the requested object from.
    const { getObjectContext } = event;
    const { outputRoute, outputToken, inputS3Url } = getObjectContext;

    // Download the object from S3 and process it as a stream, because it might be a huge object and we don't want to
    // buffer it in memory. Note the use of 'await' because we want to wait for 'writeGetObjectResponse' to finish 
    // before we can exit the Lambda function. 
    await axios({
        method: 'GET',
        url: inputS3Url,
        responseType: 'stream',
    }).then(
        // Gzip the stream.
        response => response.data.pipe(zlib.createGzip())
    ).then(
        // Finally send the gzip-ed stream back to the client.
        stream => s3.writeGetObjectResponse({
            RequestRoute: outputRoute,
            RequestToken: outputToken,
            Body: stream,
            ContentType: "text/plain",
            ContentEncoding: "gzip",
        }).promise()
    );

    // Gracefully exit the Lambda function.
    return { statusCode: 200 };
}
```

------

**注記**  
S3 Object Lambda では、発信者に完全なレスポンスを送信するのに最大 60 秒かかります。`WriteGetObjectResponse` リクエストの場合、実際の利用可能な時間は短くなる可能性があります。例えば、Lambda 関数のタイムアウトが 60 秒未満である可能性があります。それ以外にも、発信者のタイムアウトがより厳しい場合があります。

元の発信者が HTTP ステータスコード 500 以外のレスポンス (内部サーバエラー) を受信するには、`WriteGetObjectResponse` コールが完了する必要があります。`WriteGetObjectResponse` API オペレーションが呼び出される前に、Lambda 関数が例外的に、またはその他の方法で返された場合、元の発信者は 500 (内部サーバーエラー) レスポンスを受け取ります。レスポンスが完了するまでの間にスローされた例外は、発信者へのレスポンスが切り捨てられます。Lambda 関数が `WriteGetObjectResponse` API コールから HTTP ステータスコード 200 (OK) レスポンスを受信した場合、元の発信者は完全なリクエストを送信しています。例外がスローされたかどうかにかかわらず、Lambda 関数のレスポンスは S3 Object Lambda では無視されます。

この `WriteGetObjectResponse` API オペレーションを呼び出すとき、Amazon S3 はイベントコンテキストからのルートトークンとリクエストトークンを必要とします。詳細については、「[イベントコンテキストの形式と使用法](olap-event-context.md)」を参照してください。

ルートトークンとリクエストトークンのパラメータは、`WriteGetObjectResult` レスポンスを元の発信者に接続するために必要です。通常、500 (内部サーバーエラー) レスポンスを再試行するのが適切ですが、リクエストトークンはワンタイムトークンであることに注意してください。それ以降に使用を試みると、HTTP ステータスコード 400 (Bad Request) レスポンスが返されることになる可能性があります。ルートトークンとリクエストトークンを使用した `WriteGetObjectResponse` への呼び出しは、呼び出された Lambda 関数から作成する必要はありませんが、同じアカウント内のアイデンティティによって作成する必要があります。この呼び出しは、Lambda 関数の実行を完了する前に完了する必要があります。

## Lambdaでの `HeadObject` リクエストの処理
<a name="olap-headobject"></a>

このセクションでは、Object Lambda アクセスポイントが `HeadObject` 用に Lambda 関数を呼び出すように設定されていることを前提としています。Lambda は `headObjectContext` というキーを含む JSON ペイロードを受け取ります。コンテキスト内には、`inputS3Url` というプロパティが 1 つあります。これは、`HeadObject` をサポートしているアクセスポイントの署名付き URL です。

署名付き URL に次のプロパティが指定されている場合、署名付き URL にはそれらが含まれます。
+ `versionId` (クエリパラメータ内)
+ `requestPayer` (`x-amz-request-payer` ヘッダー内)
+ `expectedBucketOwner` (`x-amz-expected-bucket-owner` ヘッダー内)

他のプロパティは署名付きではないため、含まれません。ヘッダーとして送信される署名されていないオプションは、`userRequest` ヘッダーにある署名付き URL を呼び出すときに、手動でリクエストに追加できます。サーバー側の暗号化オプションは、`HeadObject` ではサポートされていません。

リクエスト構文 URI パラメータについては、「*Amazon Simple Storage Service API リファレンス*」の「[https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html)」を参照してください。

次の例は、`HeadObject` の Lambda JSON 入力ペイロードを示しています。

```
{
  "xAmzRequestId": "requestId",
  "**headObjectContext**": {
    "**inputS3Url**": "https://my-s3-ap-111122223333.s3-accesspoint.us-east-1.amazonaws.com/example?X-Amz-Security-Token=<snip>"
  },
  "configuration": {
       "accessPointArn": "arn:aws:s3-object-lambda:us-east-1:111122223333:accesspoint/example-object-lambda-ap",
       "supportingAccessPointArn": "arn:aws:s3:us-east-1:111122223333:accesspoint/example-ap",
       "payload": "{}"
  },
  "userRequest": {
       "url": "https://object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com/example",
       "headers": {
           "Host": "object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com",
           "Accept-Encoding": "identity",
           "X-Amz-Content-SHA256": "e3b0c44298fc1example"
       }
   },
   "userIdentity": {
       "type": "AssumedRole",
       "principalId": "principalId",
       "arn": "arn:aws:sts::111122223333:assumed-role/Admin/example",       
       "accountId": "111122223333",
       "accessKeyId": "accessKeyId",
       "sessionContext": {
            "attributes": {
            "mfaAuthenticated": "false",
            "creationDate": "Wed Mar 10 23:41:52 UTC 2021"
       },
       "sessionIssuer": {
            "type": "Role",
            "principalId": "principalId",
            "arn": "arn:aws:iam::111122223333:role/Admin",
            "accountId": "111122223333",
            "userName": "Admin"
            }
       }
    },
  "protocolVersion": "1.00"
}
```

Lambda 関数は、`HeadObject` 呼び出しで返されるヘッダーと値を含む JSON オブジェクトを返します。

次の例は、`HeadObject` の Lambda レスポンス JSON の構造を示しています。

```
{
    "statusCode": <number>; // Required
    "errorCode": <string>;
    "errorMessage": <string>;
    "headers": {
        "Accept-Ranges": <string>,
        "x-amz-archive-status": <string>,
        "x-amz-server-side-encryption-bucket-key-enabled": <boolean>,
        "Cache-Control": <string>,
        "Content-Disposition": <string>,
        "Content-Encoding": <string>,
        "Content-Language": <string>,
        "Content-Length": <number>, // Required
        "Content-Type": <string>,
        "x-amz-delete-marker": <boolean>,
        "ETag": <string>,
        "Expires": <string>,
        "x-amz-expiration": <string>,
        "Last-Modified": <string>,
        "x-amz-missing-meta": <number>,
        "x-amz-object-lock-mode": <string>,
        "x-amz-object-lock-legal-hold": <string>,
        "x-amz-object-lock-retain-until-date": <string>,
        "x-amz-mp-parts-count": <number>,
        "x-amz-replication-status": <string>,
        "x-amz-request-charged": <string>,
        "x-amz-restore": <string>,
        "x-amz-server-side-encryption": <string>,
        "x-amz-server-side-encryption-customer-algorithm": <string>,
        "x-amz-server-side-encryption-aws-kms-key-id": <string>,
        "x-amz-server-side-encryption-customer-key-MD5": <string>,
        "x-amz-storage-class": <string>,
        "x-amz-tagging-count": <number>,
        "x-amz-version-id": <string>,
        <x-amz-meta-headers>: <string>, // user-defined metadata 
        "x-amz-meta-meta1": <string>, // example of the user-defined metadata header, it will need the x-amz-meta prefix
        "x-amz-meta-meta2": <string>
        ...
    };
}
```

次の例は、JSON を返す前に必要に応じてヘッダー値を変更することにより、署名付き URL を使用してレスポンスを入力する方法を示しています。

------
#### [ Python ]



```
import requests

def lambda_handler(event, context):
    print(event)
    
    # Extract the presigned URL from the input.
    s3_url = event["headObjectContext"]["inputS3Url"]

    # Get the head of the object from S3.     
    response = requests.head(s3_url)
    
    # Return the error to S3 Object Lambda (if applicable).           
    if (response.status_code >= 400):
        return {
            "statusCode": response.status_code,
            "errorCode": "RequestFailure",                         
            "errorMessage": "Request to S3 failed"    
    }
    
    # Store the headers in a dictionary.
    response_headers = dict(response.headers)

    # This obscures Content-Type in a transformation, it is optional to add
    response_headers["Content-Type"] = "" 

    # Return the headers to S3 Object Lambda.     
    return {
        "statusCode": response.status_code,
        "headers": response_headers     
        }
```

------

## Lambda での `ListObjects` リクエストの使用
<a name="olap-listobjects"></a>

このセクションでは、Object Lambda アクセスポイントが `ListObjects` 用に Lambda 関数を呼び出すように設定されていることを前提としています。Lambda は、`listObjectsContext` という新しいオブジェクトを持つ JSON ペイロードを受け取ります。`listObjectsContext` には、`inputS3Url` という単一のプロパティが含まれており、これは `ListObjects` をサポートしているアクセスポイント用の署名付き URL です。

`GetObject` や `HeadObject` とは異なり、署名付き URL には、次のプロパティが指定されている場合はそれらが含まれます。
+ すべてのクエリパラメータ
+ `requestPayer` (`x-amz-request-payer` ヘッダー内) 
+ `expectedBucketOwner` (`x-amz-expected-bucket-owner` ヘッダー内)

リクエスト構文 URI パラメータについては、「*Amazon Simple Storage Service API リファレンス*」の「[https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html)」を参照してください。

**重要**  
アプリケーションを開発する場合は、新しいバージョンの [ListObjectSv2](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html) を使用することをお勧めします。Amazon S3 は、下位互換性のために、引き続き `ListObjects` をサポートしています。

次の例は、`ListObjects` の Lambda JSON 入力ペイロードを示しています。

```
{
    "xAmzRequestId": "requestId",
     "**listObjectsContext**": {
     "**inputS3Url**": "https://my-s3-ap-111122223333.s3-accesspoint.us-east-1.amazonaws.com/?X-Amz-Security-Token=<snip>",
     },
    "configuration": {
        "accessPointArn": "arn:aws:s3-object-lambda:us-east-1:111122223333:accesspoint/example-object-lambda-ap",
        "supportingAccessPointArn": "arn:aws:s3:us-east-1:111122223333:accesspoint/example-ap",
        "payload": "{}"
    },
    "userRequest": {
        "url": "https://object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com/example",
        "headers": {
            "Host": "object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com",
            "Accept-Encoding": "identity",
            "X-Amz-Content-SHA256": "e3b0c44298fc1example"
        }
    },
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "principalId",
        "arn": "arn:aws:sts::111122223333:assumed-role/Admin/example",
        "accountId": "111122223333",
        "accessKeyId": "accessKeyId",
        "sessionContext": {
            "attributes": {
                "mfaAuthenticated": "false",
                "creationDate": "Wed Mar 10 23:41:52 UTC 2021"
            },
            "sessionIssuer": {
                "type": "Role",
                "principalId": "principalId",
                "arn": "arn:aws:iam::111122223333:role/Admin",
                "accountId": "111122223333",
                "userName": "Admin"
            }
        }
    },
  "protocolVersion": "1.00"
}
```

Lambda 関数は、S3 Object Lambda から返されるステータスコード、XML 結果のリスト、またはエラー情報を含む JSON オブジェクトを返します。

S3 Object Lambda は `listResultXml` の処理も検証もせず、代わりに `ListObjects` 呼び出し元に転送します。`listBucketResult` については、S3 Object Lambda は特定のプロパティが特定のタイプであることを想定し、解析できない場合は例外をスローします。 `listResultXml` および `listBucketResult` を同時に提供することはできません。

次の例は、署名付き URL を使用して Amazon S3 を呼び出し、その結果を使用してエラーチェックを含むレスポンスを入力する方法を示しています。

------
#### [ Python ]

```
import requests 
import xmltodict

def lambda_handler(event, context):
    # Extract the presigned URL from the input.
    s3_url = event["listObjectsContext"]["inputS3Url"]


    # Get the head of the object from Amazon S3.
    response = requests.get(s3_url)

    # Return the error to S3 Object Lambda (if applicable).
    if (response.status_code >= 400):
        error = xmltodict.parse(response.content)
        return {
            "statusCode": response.status_code,
            "errorCode": error["Error"]["Code"],
            "errorMessage": error["Error"]["Message"]
        }

    # Store the XML result in a dict.
    response_dict = xmltodict.parse(response.content)

    # This obscures StorageClass in a transformation, it is optional to add
    for item in response_dict['ListBucketResult']['Contents']:
        item['StorageClass'] = ""

    # Convert back to XML.
    listResultXml = xmltodict.unparse(response_dict)
    
    # Create response with listResultXml.
    response_with_list_result_xml = {
        'statusCode': 200,
        'listResultXml': listResultXml
    }

    # Create response with listBucketResult.
    response_dict['ListBucketResult'] = sanitize_response_dict(response_dict['ListBucketResult'])
    response_with_list_bucket_result = {
        'statusCode': 200,
        'listBucketResult': response_dict['ListBucketResult']
    }

    # Return the list to S3 Object Lambda.
    # Can return response_with_list_result_xml or response_with_list_bucket_result
    return response_with_list_result_xml

# Converting the response_dict's key to correct casing
def sanitize_response_dict(response_dict: dict):
    new_response_dict = dict()
    for key, value in response_dict.items():
        new_key = key[0].lower() + key[1:] if key != "ID" else 'id'
        if type(value) == list:
            newlist = []
            for element in value:
                if type(element) == type(dict()):
                    element = sanitize_response_dict(element)
                newlist.append(element)
            value = newlist
        elif type(value) == dict:
            value = sanitize_response_dict(value)
        new_response_dict[new_key] = value
    return new_response_dict
```

------

次の例は、`ListObjects` の Lambda レスポンス JSON の構造を示しています。

```
{ 
  "statusCode": <number>; // Required
  "errorCode": <string>;
  "errorMessage": <string>;
  "listResultXml": <string>; // This can also be Error XML string in case S3 returned error response when calling the pre-signed URL

  "listBucketResult": {  // listBucketResult can be provided instead of listResultXml, however they can not both be provided in the JSON response  
        "name": <string>,  // Required for 'listBucketResult'
        "prefix": <string>,  
        "marker": <string>, 
        "nextMarker": <string>, 
        "maxKeys": <int>,   // Required for 'listBucketResult'
        "delimiter": <string>, 
        "encodingType": <string>  
        "isTruncated": <boolean>,  // Required for 'listBucketResult'
        "contents": [  { 
            "key": <string>,  // Required for 'content'
            "lastModified": <string>,  
            "eTag": <string>,  
            "checksumAlgorithm": <string>,   // CRC32,  CRC32C,  SHA1,  SHA256
            "size": <int>,   // Required for 'content'
            "owner": {  
                "displayName": <string>,  // Required for 'owner'
                "id": <string>,  // Required for 'owner'
            },  
            "storageClass": <string>  
            },  
        ...  
        ],  
        "commonPrefixes": [  {  
            "prefix": <string>   // Required for 'commonPrefix'
        },  
        ...  
        ],  
    }
}
```

## Lambda での `ListObjectsV2` リクエストの使用
<a name="olap-listobjectsv2"></a>

このセクションでは、Object Lambda アクセスポイントが `ListObjectsV2` 用に Lambda 関数を呼び出すように設定されていることを前提としています。Lambda は、`listObjectsV2Context` という新しいオブジェクトを持つ JSON ペイロードを受け取ります。`listObjectsV2Context` には、`inputS3Url` という単一のプロパティが含まれており、これは `ListObjectsV2` をサポートしているアクセスポイント用の署名付き URL です。

`GetObject` や `HeadObject` とは異なり、署名付き URL には、次のプロパティが指定されている場合はそれらが含まれます。
+ すべてのクエリパラメータ
+ `requestPayer` (`x-amz-request-payer` ヘッダー内) 
+ `expectedBucketOwner` (`x-amz-expected-bucket-owner` ヘッダー内)

リクエスト構文 URI パラメータについては、「*Amazon Simple Storage Service API リファレンス*」の「[https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html)」を参照してください。

次の例は、`ListObjectsV2` の Lambda JSON 入力ペイロードを示しています。

```
{
    "xAmzRequestId": "requestId",
     "**listObjectsV2Context**": {
     "**inputS3Url**": "https://my-s3-ap-111122223333.s3-accesspoint.us-east-1.amazonaws.com/?list-type=2&X-Amz-Security-Token=<snip>",
     },
    "configuration": {
        "accessPointArn": "arn:aws:s3-object-lambda:us-east-1:111122223333:accesspoint/example-object-lambda-ap",
        "supportingAccessPointArn": "arn:aws:s3:us-east-1:111122223333:accesspoint/example-ap",
        "payload": "{}"
    },
    "userRequest": {
        "url": "https://object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com/example",
        "headers": {
            "Host": "object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com",
            "Accept-Encoding": "identity",
            "X-Amz-Content-SHA256": "e3b0c44298fc1example"
        }
    },
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "principalId",
        "arn": "arn:aws:sts::111122223333:assumed-role/Admin/example",
        "accountId": "111122223333",
        "accessKeyId": "accessKeyId",
        "sessionContext": {
            "attributes": {
                "mfaAuthenticated": "false",
                "creationDate": "Wed Mar 10 23:41:52 UTC 2021"
            },
            "sessionIssuer": {
                "type": "Role",
                "principalId": "principalId",
                "arn": "arn:aws:iam::111122223333:role/Admin",
                "accountId": "111122223333",
                "userName": "Admin"
            }
        }
    },
  "protocolVersion": "1.00" 
}
```

Lambda 関数は、S3 Object Lambda から返されるステータスコード、XML 結果のリスト、またはエラー情報を含む JSON オブジェクトを返します。

S3 Object Lambda は `listResultXml` の処理も検証もせず、代わりに `ListObjectsV2` 呼び出し元に転送します。`listBucketResult` については、S3 Object Lambda は特定のプロパティが特定のタイプであることを想定し、解析できない場合は例外をスローします。 `listResultXml` および `listBucketResult` を同時に提供することはできません。

次の例は、署名付き URL を使用して Amazon S3 を呼び出し、その結果を使用してエラーチェックを含むレスポンスを入力する方法を示しています。

------
#### [ Python ]

```
import requests 
import xmltodict

def lambda_handler(event, context):
    # Extract the presigned URL from the input.
    s3_url = event["listObjectsV2Context"]["inputS3Url"]


    # Get the head of the object from Amazon S3.
    response = requests.get(s3_url)

    # Return the error to S3 Object Lambda (if applicable).
    if (response.status_code >= 400):
        error = xmltodict.parse(response.content)
        return {
            "statusCode": response.status_code,
            "errorCode": error["Error"]["Code"],
            "errorMessage": error["Error"]["Message"]
        }

    # Store the XML result in a dict.
    response_dict = xmltodict.parse(response.content)

    # This obscures StorageClass in a transformation, it is optional to add
    for item in response_dict['ListBucketResult']['Contents']:
        item['StorageClass'] = ""

    # Convert back to XML.
    listResultXml = xmltodict.unparse(response_dict)
    
    # Create response with listResultXml.
    response_with_list_result_xml = {
        'statusCode': 200,
        'listResultXml': listResultXml
    }

    # Create response with listBucketResult.
    response_dict['ListBucketResult'] = sanitize_response_dict(response_dict['ListBucketResult'])
    response_with_list_bucket_result = {
        'statusCode': 200,
        'listBucketResult': response_dict['ListBucketResult']
    }

    # Return the list to S3 Object Lambda.
    # Can return response_with_list_result_xml or response_with_list_bucket_result
    return response_with_list_result_xml

# Converting the response_dict's key to correct casing
def sanitize_response_dict(response_dict: dict):
    new_response_dict = dict()
    for key, value in response_dict.items():
        new_key = key[0].lower() + key[1:] if key != "ID" else 'id'
        if type(value) == list:
            newlist = []
            for element in value:
                if type(element) == type(dict()):
                    element = sanitize_response_dict(element)
                newlist.append(element)
            value = newlist
        elif type(value) == dict:
            value = sanitize_response_dict(value)
        new_response_dict[new_key] = value
    return new_response_dict
```

------

次の例は、`ListObjectsV2` の Lambda レスポンス JSON の構造を示しています。

```
{  
    "statusCode": <number>; // Required  
    "errorCode": <string>;  
    "errorMessage": <string>;  
    "listResultXml": <string>; // This can also be Error XML string in case S3 returned error response when calling the pre-signed URL  
  
    "listBucketResult": {  // listBucketResult can be provided instead of listResultXml, however they can not both be provided in the JSON response 
        "name": <string>, // Required for 'listBucketResult'  
        "prefix": <string>,  
        "startAfter": <string>,  
        "continuationToken": <string>,  
        "nextContinuationToken": <string>,
        "keyCount": <int>, // Required for 'listBucketResult'  
        "maxKeys": <int>, // Required for 'listBucketResult'  
        "delimiter": <string>,  
        "encodingType": <string>  
        "isTruncated": <boolean>, // Required for 'listBucketResult'  
        "contents": [ {  
            "key": <string>, // Required for 'content'  
            "lastModified": <string>,  
            "eTag": <string>,  
            "checksumAlgorithm": <string>, // CRC32, CRC32C, SHA1, SHA256  
            "size": <int>, // Required for 'content'  
            "owner": {  
                "displayName": <string>, // Required for 'owner'  
                "id": <string>, // Required for 'owner'  
            },  
            "storageClass": <string>  
            },  
            ...  
        ],  
        "commonPrefixes": [ {  
            "prefix": <string> // Required for 'commonPrefix'  
            },  
        ...  
        ],  
    }  
}
```

# イベントコンテキストの形式と使用法
<a name="olap-event-context"></a>

**注記**  
2025 年 11 月 7 日現在、S3 Object Lambda は、現在サービスを使用している既存のお客様、および一部の AWS パートナーネットワーク (APN) パートナーのみが利用できます。S3 Object Lambda と同様の機能の詳細については、「[Amazon S3 Object Lambda availability change](https://docs.aws.amazon.com/AmazonS3/latest/userguide/amazons3-ol-change.html)」を参照してください。

Amazon S3 Object Lambda は、AWS Lambda 関数に渡されたイベントで行われたリクエストに関するコンテキストを提供します。リクエストの例を次に示します。フィールドの説明は例の後に含まれています。

```
{
    "xAmzRequestId": "requestId",
    "getObjectContext": {
        "inputS3Url": "https://my-s3-ap-111122223333.s3-accesspoint.us-east-1.amazonaws.com/example?X-Amz-Security-Token=<snip>",
        "outputRoute": "io-use1-001",
        "outputToken": "OutputToken"
    },
    "configuration": {
        "accessPointArn": "arn:aws:s3-object-lambda:us-east-1:111122223333:accesspoint/example-object-lambda-ap",
        "supportingAccessPointArn": "arn:aws:s3:us-east-1:111122223333:accesspoint/example-ap",
        "payload": "{}"
    },
    "userRequest": {
        "url": "https://object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com/example",
        "headers": {
            "Host": "object-lambda-111122223333.s3-object-lambda.us-east-1.amazonaws.com",
            "Accept-Encoding": "identity",
            "X-Amz-Content-SHA256": "e3b0c44298fc1example"
        }
    },
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "principalId",
        "arn": "arn:aws:sts::111122223333:assumed-role/Admin/example",
        "accountId": "111122223333",
        "accessKeyId": "accessKeyId",
        "sessionContext": {
            "attributes": {
                "mfaAuthenticated": "false",
                "creationDate": "Wed Mar 10 23:41:52 UTC 2021"
            },
            "sessionIssuer": {
                "type": "Role",
                "principalId": "principalId",
                "arn": "arn:aws:iam::111122223333:role/Admin",
                "accountId": "111122223333",
                "userName": "Admin"
            }
        }
    },
    "protocolVersion": "1.00"
}
```

リクエストには次のフィールドが含まれます。
+ `xAmzRequestId` － このリクエストの Amazon S3 リクエスト ID。デバッグに役立つように、この値をログに記録することをお勧めします。
+ `getObjectContext` － Amazon S3 および S3 Object Lambda への接続に関する入力および出力の詳細。
  + `inputS3Url` － Amazon S3 から元のオブジェクトを取得するために使用できる署名付き URL。URL は元の発信者のアイデンティティを使用して署名され、URL が使用されるときにそのユーザーのアクセス許可が適用されます。URL に署名されたヘッダーがある場合、Lambda 関数では、`Host` ヘッダーを除き、Amazon S3 への呼び出しにこれらのヘッダーを含める必要があります。
  + `outputRoute` – Lambda 関数が を呼び出すときに S3 Object Lambda URL に追加されるルーティングトークン。`WriteGetObjectResponse`
  + `outputToken` - `WriteGetObjectResponse` 呼び出しを元の発信者と一致させるために、S3 Object Lambda によって使用される不透明なトークン。
+ `configuration` - Object Lambda アクセスポイントに関する設定情報。
  + `accessPointArn` - このリクエストを受信した Object Lambda アクセスポイントの Amazon リソースネーム (ARN)。
  + `supportingAccessPointArn` - Object Lambda アクセスポイント設定で指定されているサポートアクセスポイントの ARN。
  + `payload` - Object Lambda アクセスポイント設定に適用されるカスタムデータ。S3 Object Lambda はこのデータを不透明な文字列として扱うため、使用前にデコードする必要がある場合があります。
+ `userRequest` - S3 Object Lambda への元の呼び出しに関する情報。
  + `url` - S3 Object Lambda で受信したリクエストのデコードされた URL。認可関連のクエリパラメータは除きます。
  + `headers` - HTTP ヘッダーと元の呼び出しからの値を含む文字列への文字列マップ。認可関連のヘッダーは含まれません。同じヘッダーが複数回表示される場合、同じヘッダーの各インスタンスからの値は、コンマ区切りのリストに結合されます。元のヘッダーの大文字と小文字は、このマップに保持されます。
+ `userIdentity` – S3 Object Lambda への呼び出しを行ったアイデンティティの詳細。詳細については、**「AWS CloudTrail ユーザーガイド」の「[証跡のデータイベントの記録](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-data-events-with-cloudtrail.html)」を参照してください。
  + `type` – アイデンティティのタイプ。
  + `accountId` - アイデンティティが属するAWS アカウント。
  + `userName` - 呼び出しを行ったアイデンティティのわかりやすい名前。
  + `principalId` - 呼び出しを行ったアイデンティティの一意の識別子。
  + `arn` – 呼び出しを行ったプリンシパルの ARN。ARN の最後のセクションには、呼び出しを行ったユーザーまたはロールが含まれています。
  + `sessionContext` - リクエストが、一時的セキュリティ認証情報を使用して行われた場合、このエレメントはこれらの認証情報のために作成されたセッションに関する情報を提供します。
  + `invokedBy` – Amazon EC2 Auto Scaling や AWS Elastic Beanstalk など、リクエストを行った AWS のサービス の名前。
  + `sessionIssuer` - リクエストが一時的セキュリティ認証情報を使用して行われた場合、このエレメントは認証情報がどのように取得されたかに関する情報を提供します。
+ `protocolVersion` – 提供されるコンテキストのバージョン ID。このフィールドの形式は `{Major Version}.{Minor Version}` です。マイナーバージョン番号は、常に 2 桁の数字です。フィールドのセマンティクスを削除または変更する場合は、メジャーバージョンバンプが必要となり、アクティブなオプトインが必要になります。Amazon S3 ではいつでも新しいフィールドを追加できます。この時点で、マイナーバージョンのバンプが発生する可能性があります。ソフトウェアのロールアウトの性質上、一度に複数のマイナーバージョンが使用されている場合があります。

# Range および partNumber ヘッダーの操作
<a name="range-get-olap"></a>

**注記**  
2025 年 11 月 7 日現在、S3 Object Lambda は、現在サービスを使用している既存のお客様、および一部の AWS パートナーネットワーク (APN) パートナーのみが利用できます。S3 Object Lambda と同様の機能の詳細については、「[Amazon S3 Object Lambda availability change](https://docs.aws.amazon.com/AmazonS3/latest/userguide/amazons3-ol-change.html)」を参照してください。

Amazon S3 Object Lambda で大規模なオブジェクトを操作する場合は、`Range` HTTP ヘッダーを使用して、オブジェクトから指定されたバイト範囲をダウンロードできます。同じオブジェクトのさまざまなバイト範囲をフェッチするには、Amazon S3 への同時接続を使用できます。また、オブジェクトの指定されたパートに対して範囲リクエストを実行する `partNumber` パラメータ(1～10,000 の整数) を指定することもできます。

`Range` または `partNumber` のパラメータを含んだリクエストを処理するには、複数の方法があるため、S3 オブジェクト Lambda ではこれらのパラメータを変換されたオブジェクトに適用しません。代わりに、AWS Lambda 関数は、アプリケーションで必要に応じてこの機能を実装する必要があります。

S3 Object Lambda で `Range` および `partNumber` パラメータを使用するには、次の操作を行います。
+ Object Lambda アクセスポイントの設定でこれらのパラメータを有効にします。
+ これらのパラメータを含むリクエストを処理できる Lambda 関数を作成します。

次のステップでそのやり方を説明します。

## ステップ 1: Object Lambda アクセスポイントの設定
<a name="range-get-olap-step-1"></a>

デフォルトでは、オブジェクト Lambda アクセスポイントは、ヘッダーまたはクエリパラメータに `Range` または `partNumber` パラメータを含む `GetObject` または `HeadObject` リクエストに対して、HTTP ステータスコード 501 (未実装) エラーで応答します。

Object Lambda アクセスポイントがこのようなリクエストを有効にするには、Object Lambda アクセスポイント設定の `AllowedFeatures` セクションに `GetObject-Range`、`GetObject-PartNumber`、`HeadObject-Range`、または `HeadObject-PartNumber` を含める必要があります。Object Lambda アクセスポイントの設定の更新の詳細については、「[Object Lambda アクセスポイントの作成](olap-create.md)」を参照してください。

## ステップ 2: Lambda 関数で `Range` または `partNumber` 処理を実装する
<a name="range-get-olap-step-2"></a>

Object Lambda アクセスポイントが範囲 `GetObject` または `HeadObject` のリクエストで Lambda 関数を呼び出すとき、`Range` または `partNumber` パラメータはイベントコンテキストに含まれます。イベントコンテキストでのパラメータの場所は、次の表で説明するように、使用されたパラメータと Object Lambda アクセスポイントへの元のリクエストにどのように Lambda 含まれていたかによって異なります。


| パラメータ | イベントコンテキストの場所 | 
| --- | --- | 
|  `Range` (ヘッダー)  |  `userRequest.headers.Range`  | 
|  `Range` (クエリパラメータ)  |  `userRequest.url` (クエリパラメータ `Range`)  | 
|  `partNumber`  |  `userRequest.url` (クエリパラメータ `partNumber`)  | 

**重要**  
指定された Object Lambda アクセスポイントの署名付き URL には、元のリクエストの `Range` または `partNumber` パラメータが含まれていません。AWS Lambda 関数でこれらのパラメータを処理する方法については、以下のオプションを参照してください。

`Range` または `partNumber` の値を抽出した後に、アプリケーションのニーズに基づいて、次のいずれかの方法を使用できます。

1. **リクエストされた `Range` または `partNumber` を変換されたオブジェクトにマッピングします (推奨)。**

   `Range` または `partNumber` リクエストを処理する最も確実な方法は、以下を実行することです。
   + Amazon S3 から完全なオブジェクトを取得します。
   + オブジェクトを変換します。
   + リクエストされた `Range` または `partNumber` パラメータを変換後のオブジェクトに適用します。

   これを行うには、指定された署名付き URL を使用して Amazon S3 からオブジェクト全体をフェッチし、必要に応じてオブジェクトを処理します。例の Lambda 関数では、この方法で `Range` パラメータを設定し、AWS サンプル GitHub リポジトリの[「このサンプル」](https://github.com/aws-samples/amazon-s3-object-lambda-default-configuration/blob/main/function/nodejs_20_x/src/response/range_mapper.ts)を参照してください。

1. **リクエストされた `Range` を署名付き URL にマッピングします。**

   場合によっては、Lambda 関数でリクエストされた `Range` を署名済み URL に直接マッピングして、Amazon S3 からオブジェクトの一部のみを取得できます。このアプローチは、変換が次の両方の条件を満たしている場合にのみ適切です。

   1. 変換関数は、部分的なオブジェクト範囲に適用できます。

   1. 変換関数の前または後に `Range` パラメータを指定すると、同じ変換後のオブジェクトになります。

   たとえば、ASCII エンコードオブジェクト内のすべての文字を大文字に変換する変換関数は、上記の両方の条件を満たします。変換はオブジェクトの一部に適用でき、変換前に `Range` パラメータを適用すると、変換後にパラメータを適用するのと同じ結果が得られます。

   対照的に、ASCII エンコードされたオブジェクトの文字を反転する関数は、これらの条件を満たしていません。このような関数は、部分的なオブジェクト範囲に適用できるため、基準 1 を満たしています。ただし、基準 2 を満たしていません。なぜなら、`Range` パラメータを変換前に適用した場合と、変換後にパラメータを適用する場合とは結果が異なるためです。

   コンテンツ `abcdefg` を含むオブジェクトの最初の 3 文字に関数を適用するリクエストを考えてみましょう。変換前にの `Range` パラメータを適用すると `abc` のみが取得され、その後、データを逆にして戻すと `cba` が取得されます。しかし、変換後にパラメータが適用された場合、関数はオブジェクト全体を取得し、それを反転し、`Range` パラメータを適用して、`gfe` を返します。これらの結果は異なるため、この関数は Amazon S3 からオブジェクトを取得する際に、`Range` パラメータを適用すべきではありません。代わりに、オブジェクト全体を取得し、変換を実行してから、`Range` パラメータを適用する必要があります。
**警告**  
多くの場合、`Range` パラメータを署名済み URL に適用すると、Lambda 関数またはリクエスト元のクライアントによる予期しない動作が発生します。Amazon S3 から部分的なオブジェクトのみを取得するときにアプリケーションが正常に動作することが確実でない限り、アプローチ A で前述したように、完全なオブジェクトを取得して変換することをお勧めします。

   アプリケーションがアプローチ B の基準を満たしていれば、要求されたオブジェクト範囲のみをフェッチし、その範囲で変換を実行することで、AWS Lambda 関数を単純化することができます。

   次の Java コードの例では、次の処理を実行する方法を示します。
   + `GetObject` リクエストから `Range` ヘッダーを取得します。
   + Lambda が Amazon S3 からリクエストされた範囲を取得するために使用できる署名付き URL に `Range` ヘッダーを追加します。

   ```
   private HttpRequest.Builder applyRangeHeader(ObjectLambdaEvent event, HttpRequest.Builder presignedRequest) {
       var header = event.getUserRequest().getHeaders().entrySet().stream()
               .filter(e -> e.getKey().toLowerCase(Locale.ROOT).equals("range"))
               .findFirst();
   
       // Add check in the query string itself.
       header.ifPresent(entry -> presignedRequest.header(entry.getKey(), entry.getValue()));
       return presignedRequest;
   }
   ```