

# Escrever funções do Lambda para pontos de acesso do S3 Object Lambda
<a name="olap-writing-lambda"></a>

**nota**  
Desde 7 de novembro de 2025, o S3 Object Lambda está disponível somente para clientes existentes que estão usando o serviço no momento, bem como para parceiros selecionados da Rede de Parceiros da AWS (APN). Para recursos semelhantes ao S3 Object Lambda, saiba mais aqui: [Amazon S3 Object Lambda availability change](https://docs.aws.amazon.com/AmazonS3/latest/userguide/amazons3-ol-change.html).

Essa seção apresenta detalhes de como escrever funções do AWS Lambda para usar com pontos de acesso do Amazon S3 Object Lambda.

Para saber mais sobre procedimentos completos para algumas tarefas do S3 Object Lambda, consulte o seguinte:
+ [Tutorial: Como transformar dados para sua aplicação com o S3 Object Lambda](tutorial-s3-object-lambda-uppercase.md)
+ [Tutorial: Detectar e editar dados PII com o S3 Object Lambda e o Amazon Comprehend](tutorial-s3-object-lambda-redact-pii.md)
+ [Tutorial: Using S3 Object Lambda to dynamically watermark images as they are retrieved (Tutorial: Como usar o S3 Object Lambda para colocar marca d’água em imagens de maneira dinâmica à medida que são recuperadas](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**
+ [Trabalhar com solicitações `GetObject` no Lambda](#olap-getobject-response)
+ [Trabalhar com solicitações `HeadObject` no Lambda](#olap-headobject)
+ [Trabalhar com solicitações `ListObjects` no Lambda](#olap-listobjects)
+ [Trabalhar com solicitações `ListObjectsV2` no Lambda](#olap-listobjectsv2)
+ [Formato e uso de contexto de evento](olap-event-context.md)
+ [Trabalhar com cabeçalhos Range e partNumber](range-get-olap.md)

## Trabalhar com solicitações `GetObject` no Lambda
<a name="olap-getobject-response"></a>

Esta seção pressupõe que seu ponto de acesso do Object Lambda está configurado para chamar a função do Lambda para `GetObject`. O S3 Object Lambda inclui a operação de API do Amazon S3, `WriteGetObjectResponse`, que permite que a função do Lambda apresente dados personalizados e cabeçalhos de resposta para o chamador de `GetObject`. 

`WriteGetObjectResponse` oferece controle extensivo sobre código de status, cabeçalhos de resposta e corpo de resposta, com base nas suas necessidades de processamento. Você pode usar `WriteGetObjectResponse` para responder com todo o objeto transformado, partes do objeto transformado ou outras respostas com base no contexto da sua aplicação. A seção a seguir mostra exemplos exclusivos do uso da operação da API `WriteGetObjectResponse`.
+ **Exemplo 1:** Responder com código de status HTTP 403 (Proibido) 
+ **Exemplo 2:**responda com uma imagem transformada
+ **Exemplo 3:** Transmitir conteúdo compactado

**Exemplo 1: Responder com código de status HTTP 403 (Proibido) **

Você pode usar `WriteGetObjectResponse` para responder com o código de status HTTP 403 (Proibido) com base no conteúdo do objeto.

------
#### [ 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 };
}
```

------

**Exemplo 2:responda com uma imagem transformada**

Ao executar uma transformação de imagem, talvez você ache que precisa de todos os bytes do objeto de origem antes de começar a processá-los. Nesse caso, a solicitação `WriteGetObjectResponse` retorna todo o objeto para a aplicação solicitante em uma chamada.

------
#### [ 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 };
}
```

------

**Exemplo 3: Transmitir conteúdo compactado**

Quando objetos são comprimidos, os dados compactados são produzidos de forma incremental. Consequentemente, você pode usar sua solicitação `WriteGetObjectResponse` para retornar os dados compactados assim que eles estiverem prontos. Como mostrado neste exemplo, não é necessário saber o tamanho da transformação concluída.

------
#### [ 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 };
}
```

------

**nota**  
Embora o S3 Object Lambda permita enviar uma resposta completa ao autor da chamada por meio da solicitação `WriteGetObjectResponse`, a quantidade real de tempo disponível pode ser menor. Por exemplo, o tempo limite da função do Lambda pode ser inferior a 60 segundos. Em outros casos, o autor da chamada pode ter tempos limites mais rigorosos. 

Para que o autor da chamada original receba uma resposta diferente de código de status HTTP 500 (Erro interno do servidor), a chamada `WriteGetObjectResponse` deve ser concluída. Se a função do Lambda retornar, excepcionalmente ou de outra forma, antes que a operação da API `WriteGetObjectResponse` seja chamada, o autor da chamada original receberá uma resposta 500 (Erro interno do servidor). Exceções lançadas durante o tempo necessário para concluir a resposta resultam em respostas truncadas ao autor da chamada. Se a função do Lambda recebe uma resposta com código de status HTTP 200 (OK) da chamada da API `WriteGetObjectResponse`, o autor da chamada original enviou a solicitação completa. A resposta da função do Lambda, independentemente de uma exceção ser lançada ou não, é ignorada pelo S3 Object Lambda.

Ao chamar a operação de API `WriteGetObjectResponse`, o Amazon S3 exige a rota e o token de solicitação do contexto do evento. Para obter mais informações, consulte [Formato e uso de contexto de evento](olap-event-context.md).

Os parâmetros de token de roteamento e solicitação são necessários para conectar a resposta `WriteGetObjectResult` com o autor da chamada original. Ainda que sempre seja apropriado repetir respostas 500 (Erro interno do servidor), como o token de solicitação é um token de uso único, as tentativas subsequentes de usá-lo podem resultar em respostas com código de status HTTP 400 (Solicitação inválida). Embora a chamada para `WriteGetObjectResponse` com tokens de roteamento e solicitação não precise ser feita a partir da função do Lambda invocada, ela deve ser feita por uma identidade na mesma conta. A chamada também deverá ser concluída antes que a função do Lambda termine a execução.

## Trabalhar com solicitações `HeadObject` no Lambda
<a name="olap-headobject"></a>

Esta seção pressupõe que seu ponto de acesso do Object Lambda está configurado para chamar a função do Lambda para `HeadObject`. O Lambda receberá uma carga útil JSON que contém uma chave chamada `headObjectContext`. Dentro do contexto, há uma única propriedade chamada `inputS3Url`, que é um URL pré-assinado para o ponto de acesso de suporte para `HeadObject`.

O URL pré-assinado incluirá as seguintes propriedades se elas forem especificadas: 
+ `versionId` (nos parâmetros de consulta)
+ `requestPayer` (no cabeçalho de `x-amz-request-payer`)
+ `expectedBucketOwner` (no cabeçalho de `x-amz-expected-bucket-owner`)

Outras propriedades não serão pré-assinadas e, portanto, não serão incluídas. As opções não assinadas enviadas como cabeçalhos podem ser adicionadas manualmente à solicitação ao chamar o URL pré-assinado encontrado nos cabeçalhos de `userRequest`. As opções de criptografia do lado do servidor não são compatíveis com `HeadObject`.

Para ver os parâmetros de URI da sintaxe da solicitação, consulte [https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html) na *Amazon Simple Storage Service API Reference* (Referência da API do Amazon Simple Storage Service).

O exemplo a seguir mostra uma carga útil JSON de entrada do Lambda para `HeadObject`.

```
{
  "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"
}
```

Sua função do Lambda deve retornar um objeto JSON que contém os cabeçalhos e os valores que serão retornados para a chamada de `HeadObject`.

O exemplo a seguir mostra a estrutura do JSON de resposta do Lambda para `HeadObject`.

```
{
    "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>
        ...
    };
}
```

O exemplo a seguir mostra como usar o URL pré-assinado para preencher sua resposta modificando os valores do cabeçalho conforme necessário antes de retornar o JSON.

------
#### [ 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     
        }
```

------

## Trabalhar com solicitações `ListObjects` no Lambda
<a name="olap-listobjects"></a>

Esta seção pressupõe que seu ponto de acesso do Object Lambda está configurado para chamar a função do Lambda para `ListObjects`. O Lambda receberá a carga JSON com um novo objeto chamado `listObjectsContext`. `listObjectsContext` contém uma única propriedade, `inputS3Url`, que é um URL pré-assinado para o ponto de acesso de suporte para `ListObjects`.

Ao contrário de `GetObject` e `HeadObject`, o URL pré-assinado incluirá as seguintes propriedades se elas forem especificadas:
+ Todos os parâmetros de consulta
+ `requestPayer` (no cabeçalho de `x-amz-request-payer`) 
+ `expectedBucketOwner` (no cabeçalho de `x-amz-expected-bucket-owner`)

Para ver os parâmetros de URI da sintaxe da solicitação, consulte [https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html) na *Referência da API do Amazon Simple Storage Service*.

**Importante**  
Recomendamos que você use a versão mais recente, [ListObjectsV2](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html), ao desenvolver aplicações. Para compatibilidade com versões anteriores, o Amazon S3 continua a oferecer suporte a `ListObjects`.

O exemplo a seguir mostra a carga útil JSON de entrada do Lambda para `ListObjects`.

```
{
    "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"
}
```

Sua função do Lambda deve retornar um objeto JSON que contém o código de status, o resultado XML da lista ou as informações de erro que serão retornadas do S3 Object Lambda.

O S3 Object Lambda não processa nem valida `listResultXml`. Em vez disso, o encaminha para o chamador de `ListObjects`. Para `listBucketResult`, o S3 Object Lambda espera que certas propriedades sejam de um tipo específico e lançará exceções se não puder analisá-las. `listResultXml` e `listBucketResult` não podem ser fornecidas ao mesmo tempo.

O exemplo a seguir demonstra como usar o URL pré-assinado para chamar o Amazon S3 e usar o resultado para preencher uma resposta, incluindo a verificação de erros.

------
#### [ 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
```

------

O exemplo a seguir mostra a estrutura do JSON de resposta do Lambda para `ListObjects`.

```
{ 
  "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'
        },  
        ...  
        ],  
    }
}
```

## Trabalhar com solicitações `ListObjectsV2` no Lambda
<a name="olap-listobjectsv2"></a>

Esta seção pressupõe que seu ponto de acesso do Object Lambda está configurado para chamar a função do Lambda para `ListObjectsV2`. O Lambda receberá a carga JSON com um novo objeto chamado `listObjectsV2Context`. `listObjectsV2Context` contém uma única propriedade, `inputS3Url`, que é um URL pré-assinado para o ponto de acesso de suporte para `ListObjectsV2`.

Ao contrário de `GetObject` e `HeadObject`, o URL pré-assinado incluirá as seguintes propriedades se elas forem especificadas: 
+ Todos os parâmetros de consulta
+ `requestPayer` (no cabeçalho de `x-amz-request-payer`) 
+ `expectedBucketOwner` (no cabeçalho de `x-amz-expected-bucket-owner`)

Para ver os parâmetros de URI da sintaxe da solicitação, consulte [https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html) na *Referência da API do Amazon Simple Storage Service*.

O exemplo a seguir mostra a carga útil JSON de entrada do Lambda para `ListObjectsV2`.

```
{
    "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" 
}
```

Sua função do Lambda deve retornar um objeto JSON que contém o código de status, o resultado XML da lista ou as informações de erro que serão retornadas do S3 Object Lambda.

O S3 Object Lambda não processa nem valida `listResultXml`. Em vez disso, o encaminha para o chamador de `ListObjectsV2`. Para `listBucketResult`, o S3 Object Lambda espera que certas propriedades sejam de um tipo específico e lançará exceções se não puder analisá-las. `listResultXml` e `listBucketResult` não podem ser fornecidas ao mesmo tempo.

O exemplo a seguir demonstra como usar o URL pré-assinado para chamar o Amazon S3 e usar o resultado para preencher uma resposta, incluindo a verificação de erros.

------
#### [ 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
```

------

O exemplo a seguir mostra a estrutura do JSON de resposta do Lambda para `ListObjectsV2`.

```
{  
    "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'  
            },  
        ...  
        ],  
    }  
}
```

# Formato e uso de contexto de evento
<a name="olap-event-context"></a>

**nota**  
Desde 7 de novembro de 2025, o S3 Object Lambda está disponível somente para clientes existentes que estão usando o serviço no momento, bem como para parceiros selecionados da Rede de Parceiros da AWS (APN). Para recursos semelhantes ao S3 Object Lambda, saiba mais aqui: [Amazon S3 Object Lambda availability change](https://docs.aws.amazon.com/AmazonS3/latest/userguide/amazons3-ol-change.html).

O Amazon S3 Object Lambda fornece contexto sobre a solicitação que está sendo feita no evento passado para a função AWS Lambda. Veja a seguir um exemplo de solicitação. As descrições dos campos são incluídas após o exemplo.

```
{
    "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"
}
```

Os seguintes arquivos estão incluídos na solicitação:
+ `xAmzRequestId`: o ID da solicitação do Amazon S3 para essa solicitação. Recomendamos que você registre em log esse valor para ajudar na depuração.
+ `getObjectContext`: os detalhes de entrada e saída para conexões com o Amazon S3 e o S3 Object Lambda.
  + `inputS3Url`: um URL pré-designado que pode ser usado para buscar o objeto original do Amazon S3. O URL é assinado usando a identidade do autor da chamada original, e as permissões desse usuário serão aplicadas quando o URL for usado. Se houver cabeçalhos assinados no URL, a função do Lambda deverá incluí-los na chamada para o Amazon S3, exceto para o cabeçalho `Host`.
  + `outputRoute` – um token de roteamento que é adicionado ao URL do S3 Object Lambda quando a função do Lambda chama `WriteGetObjectResponse`.
  + `outputToken`: um token opaco usado pelo S3 Object Lambda para corresponder a chamada de `WriteGetObjectResponse` com o autor da chamada original.
+ `configuration`: informações de configuração sobre o ponto de acesso do Object Lambda.
  + `accessPointArn`: o nome do recurso da Amazon (ARN) do ponto de acesso do Object Lambda que recebeu essa solicitação.
  + `supportingAccessPointArn`: o ARN do ponto de acesso de suporte especificado na configuração do ponto de acesso do Object Lambda.
  + `payload`: dados personalizados que são aplicados à configuração do ponto de acesso do Object Lambda. O S3 Object Lambda trata esses dados como uma string opaca, portanto, ela pode precisar ser decodificada antes do uso.
+ `userRequest`: informações sobre a chamada original para o S3 Object Lambda.
  + `url`: o URL decodificado da solicitação, conforme recebido pelo S3 Object Lambda, excluindo qualquer parâmetro de consulta relacionado à autorização.
  + `headers`: um mapa de string para strings contendo os cabeçalhos HTTP e seus valores da chamada original, excluindo qualquer cabeçalho relacionado à autorização. Se o mesmo cabeçalho aparecer várias vezes, os valores de cada instância do mesmo cabeçalho serão combinados em uma lista delimitada por vírgulas. O caso dos cabeçalhos originais é retido neste mapa.
+ `userIdentity`: detalhes sobre a identidade que fez a chamada para o S3 Object Lambda. Para obter mais informações, consulte [Registro eventos de dados em logs para trilhas](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-data-events-with-cloudtrail.html) no *Guia do usuário do AWS CloudTrail*.
  + `type`: o tipo da identidade.
  + `accountId`: a Conta da AWS à qual a identidade pertence.
  + `userName`: o nome amigável da identidade que fez a chamada.
  + `principalId`: o identificador exclusivo da identidade que fez a chamada.
  + `arn`: o ARN da entidade principal que fez a chamada. A última seção do ARN contém o usuário ou função que fez a chamada.
  + `sessionContext`: se a solicitação foi feita com credenciais de segurança temporárias, esse elemento fornece informações sobre a sessão que foi criada para essas credenciais.
  + `invokedBy`: o nome do serviço da AWS service (Serviço da AWS) que fez a solicitação, como o Amazon EC2 Auto Scaling ou AWS Elastic Beanstalk.
  + `sessionIssuer`: se a solicitação foi feita com credenciais de segurança temporárias, esse elemento fornece informações sobre como as credenciais foram obtidas.
+ `protocolVersion`: o ID da versão do contexto fornecido. O formato desse campo é `{Major Version}.{Minor Version}`. Os números de versão menores são sempre números de dois dígitos. Qualquer remoção ou alteração na semântica de um campo exigirá o aumento da versão principal e adesão ativa. O Amazon S3 pode adicionar novos campos a qualquer momento, no qual você pode experimentar um aumento da versão secundária. Devido à natureza das implementações de software, é possível que você veja várias versões secundárias em uso ao mesmo tempo.

# Trabalhar com cabeçalhos Range e partNumber
<a name="range-get-olap"></a>

**nota**  
Desde 7 de novembro de 2025, o S3 Object Lambda está disponível somente para clientes existentes que estão usando o serviço no momento, bem como para parceiros selecionados da Rede de Parceiros da AWS (APN). Para recursos semelhantes ao S3 Object Lambda, saiba mais aqui: [Amazon S3 Object Lambda availability change](https://docs.aws.amazon.com/AmazonS3/latest/userguide/amazons3-ol-change.html).

Ao trabalhar com objetos grandes no Amazon S3 Object Lambda, você pode usar o cabeçalho HTTP `Range` para baixar um intervalo de bytes especificado de um objeto. É possível usar conexões simultâneas ao Amazon S3 para buscar diferentes escalas de bytes no mesmo objeto. Você também pode usar o parâmetro `partNumber` (inteiro entre 1 e 10.000) que executa uma solicitação em um intervalo para a parte especificada do objeto.

Como há várias maneiras pelas quais você pode querer lidar com uma solicitação que inclua os parâmetros `Range` ou `partNumber`, o S3 Object Lambda não aplica esses parâmetros ao objeto transformado. Em vez disso, sua função do AWS Lambda deve implementar essa funcionalidade conforme necessário para a aplicação.

Para usar os parâmetros `Range` e `partNumber` com o S3 Object Lambda, faça o seguinte: 
+ Ative esses parâmetros na configuração do ponto de acesso do Object Lambda.
+ Escreva uma função do Lambda capaz de lidar com solicitações que incluam esses parâmetros.

As etapas a seguir descrevem como fazer isso.

## Etapa 1: configurar o ponto de acesso do Object Lambda
<a name="range-get-olap-step-1"></a>

Por padrão, os pontos de acesso do Object Lambda respondem com um erro de código de status HTTP 501 (não implementado) a qualquer solicitação `GetObject` ou `HeadObject` que contém um parâmetro `Range` ou `partNumber` nos cabeçalhos ou nos parâmetros de consulta. 

Para permitir que um ponto de acesso do Object Lambda aceite essas solicitações, é necessário incluir `GetObject-Range`, `GetObject-PartNumber`, `HeadObject-Range` ou `HeadObject-PartNumber` na seção `AllowedFeatures` da configuração do ponto de acesso do Object Lambda. Para obter mais informações sobre como atualizar a configuração do ponto de acesso do Object Lambda, consulte [Criar pontos de acesso do Object Lambda](olap-create.md). 

## Etapa 2: Implementar o tratamento de `Range` ou `partNumber` na função do Lambda
<a name="range-get-olap-step-2"></a>

Quando o ponto de acesso do Object Lambda invoca a função do Lambda com uma solicitação `GetObject` ou `HeadObject` em um intervalo, o parâmetro `Range` ou `partNumber` é incluído no contexto do evento. A localização do parâmetro no contexto do evento depende de qual parâmetro foi usado e de como ele foi incluído na solicitação original para o ponto de acesso do Object Lambda, conforme explicado na tabela a seguir. 


| Parâmetro | Localização do contexto do evento | 
| --- | --- | 
|  `Range` (cabeçalho)  |  `userRequest.headers.Range`  | 
|  `Range` (parâmetro de consulta)  |  `userRequest.url` (parâmetro de consulta `Range`)  | 
|  `partNumber`  |  `userRequest.url` (parâmetro de consulta `partNumber`)  | 

**Importante**  
O URL pré-assinado fornecido para o ponto de acesso do Object Lambda não contém o parâmetro `Range` ou `partNumber` da solicitação original. Veja as opções a seguir sobre como lidar com esses parâmetros na função do AWS Lambda.

Depois de extrair o valor `Range` ou `partNumber`, você poderá adotar uma das seguintes abordagens com base nas necessidades da aplicação:

1. **Mapear o `Range` ou `partNumber` solicitado para o objeto transformado (recomendado).** 

   O jeito mais confiável de lidar com solicitações `Range` e `partNumber` é fazer o seguinte: 
   + Recupere o objeto completo do Amazon S3.
   + Transforme o objeto.
   + Aplique os parâmetros `Range` ou `partNumber` solicitados ao objeto transformado.

   Para fazer isso, use o URL pré-assinado fornecido para buscar todo o objeto do Amazon S3 e, em seguida, processe o objeto conforme necessário. Para obter um exemplo de função do Lambda que processa o parâmetro `Range` dessa forma, consulte [este exemplo](https://github.com/aws-samples/amazon-s3-object-lambda-default-configuration/blob/main/function/nodejs_20_x/src/response/range_mapper.ts) no repositório de exemplos da AWS no GitHub.

1. **Associe o `Range` solicitado ao URL pré-assinado.**

   Em alguns casos, a função do Lambda pode associar o `Range` solicitado diretamente ao URL pré-assinado para recuperar apenas parte do objeto do Amazon S3. Essa abordagem será apropriada somente se sua transformação atender a ambos os seguintes critérios:

   1. Sua função de transformação pode ser aplicada a intervalos de objetos parciais.

   1. Aplicar o parâmetro `Range` antes ou depois da função de transformação ocasiona a transformação do mesmo objeto.

   Por exemplo, uma função de transformação que converte todos os caracteres em um objeto codificado em ASCII em maiúsculas atende a ambos os critérios anteriores. A transformação pode ser aplicada a parte de um objeto, e aplicar o parâmetro `Range` ou antes da transformação produz o mesmo resultado que a aplicação do parâmetro após a transformação.

   Por outro lado, uma função que inverte os caracteres em um objeto codificado em ASCII não atende a esses critérios. Essa função atende ao critério 1, pois pode ser aplicada a intervalos de objetos parciais. No entanto, ela não atende ao critério 2, porque aplicar o parâmetro `Range` antes da transformação produz resultados diferentes do que a aplicação do parâmetro após a transformação. 

   Pense em uma solicitação para aplicar a função aos três primeiros caracteres de um objeto com o conteúdo `abcdefg`. Aplicar o parâmetro `Range` antes da transformação recupera somente `abc` e, em seguida, reverte os dados, retornando `cba`. Mas se o parâmetro for aplicado após a transformação, a função recuperará todo o objeto, o reverterá e, em seguida, aplicará o parâmetro `Range`, retornando `gfe`. Como esses resultados são diferentes, essa função não deve aplicar o parâmetro `Range` ao recuperar o objeto do Amazon S3. Em vez disso, ela deve recuperar todo o objeto, executar a transformação e, somente então, aplicar o parâmetro `Range`. 
**Atenção**  
Em muitos casos, aplicar o parâmetro `Range` ao URL pré-assinado resultará em um comportamento inesperado da função do Lambda ou do cliente solicitante. A menos que você tenha certeza de que seu aplicativo funcionará corretamente ao recuperar apenas um objeto parcial do Amazon S3, recomendamos recuperar e transformar objetos completos, conforme descrito anteriormente na abordagem A. 

   Se a aplicação atender aos critérios descritos anteriormente na abordagem B, você poderá simplificar a função do AWS Lambda buscando apenas o intervalo de objetos solicitado e executando a transformação nesse intervalo. 

   O exemplo de código Java a seguir demonstra como fazer o seguinte: 
   + Recuperar o cabeçalho `Range` da solicitação `GetObject`.
   + Adicionar o cabeçalho `Range` ao URL pré-assinado que o Lambda pode usar para recuperar o intervalo solicitado do Amazon S3.

   ```
   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;
   }
   ```