

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Scrittura di funzioni Lambda per i punti di accesso Lambda per oggetti S3
<a name="olap-writing-lambda"></a>

**Nota**  
A partire dal 7 novembre 2025, S3 Object Lambda è disponibile solo per i clienti esistenti che attualmente utilizzano il servizio e per alcuni AWS partner Partner Network (APN). Per funzionalità simili a Lambda per oggetti S3, consulta [Modifica della disponibilità di Lambda per oggetti Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/amazons3-ol-change.html).

Questa sezione descrive in dettaglio come scrivere AWS Lambda funzioni da utilizzare con gli access point Amazon S3 Object Lambda.

Per informazioni sulle end-to-end procedure complete per alcune attività di S3 Object Lambda, consulta quanto segue:
+ [Tutorial: trasformazione dei dati per l'applicazione con S3 Object Lambda](tutorial-s3-object-lambda-uppercase.md)
+ [Tutorial: rilevamento e oscuramento dei dati PII con S3 Object Lambda e Amazon Comprehend](tutorial-s3-object-lambda-redact-pii.md)
+ [Tutorial: utilizzo di Lambda per oggetti S3 per aggiungere filigrane alle immagini in modo dinamico man mano che vengono recuperate](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**
+ [Utilizzo di richieste `GetObject` in Lambda](#olap-getobject-response)
+ [Utilizzo di richieste `HeadObject` in Lambda](#olap-headobject)
+ [Utilizzo di richieste `ListObjects` in Lambda](#olap-listobjects)
+ [Utilizzo di richieste `ListObjectsV2` in Lambda](#olap-listobjectsv2)
+ [Formato e utilizzo del contesto degli eventi](olap-event-context.md)
+ [Utilizzo delle intestazioni Range e partNumber](range-get-olap.md)

## Utilizzo di richieste `GetObject` in Lambda
<a name="olap-getobject-response"></a>

Questa sezione presuppone che il punto di accesso Lambda per oggetti sia configurato per richiamare la funzione Lambda per `GetObject`. S3 Object Lambda include l'operazione API Amazon S3 `WriteGetObjectResponse`, che consente alla funzione Lambda di fornire dati personalizzati e intestazioni di risposta al chiamante `GetObject`. 

`WriteGetObjectResponse` offre un ampio controllo su codice di stato, intestazioni di risposta e corpo della risposta, in base ai requisiti di elaborazione. È possibile utilizzare `WriteGetObjectResponse` per rispondere con l'intero oggetto trasformato, con parti dell'oggetto trasformato o con altre risposte in base al contesto dell'applicazione. Nella sezione seguente sono illustrati esempi univoci di utilizzo dell'operazione API `WriteGetObjectResponse`.
+ **Esempio 1:** risposta con un codice di stato HTTP 403 (Forbidden) (Accesso negato) 
+ **Esempio 2:** Rispondere con un'immagine trasformata
+ **Esempio 3:** Streaming di contenuto compresso

**Esempio 1: risposta con un codice di stato HTTP 403 (Forbidden) (Accesso negato)**

È possibile utilizzare `WriteGetObjectResponse` per rispondere con il codice di stato HTTP 403 (Non consentito) in base al contenuto dell'oggetto.

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

------

**Esempio 2:** Rispondere con un'immagine trasformata

Durante la trasformazione dell'immagine, è possibile che siano necessari tutti i byte dell'oggetto di fonte prima di poter iniziare a elaborarli. In questo caso, la tua richiesta `WriteGetObjectResponse` restituisce l'intero oggetto all'applicazione richiedente in una sola chiamata.

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

------

**Esempio 3:** Streaming di contenuto compresso

Durante la compressione degli oggetti, i dati compressi vengono prodotti in modo incrementale. Di conseguenza, puoi utilizzare la richiesta `WriteGetObjectResponse` per restituire i dati compressi non appena sono pronti. Come mostrato in questo esempio, non è necessario conoscere la lunghezza della trasformazione completata.

------
#### [ 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**  
Sebbene S3 Object Lambda consente fino a 60 secondi per inviare una risposta completa al chiamante tramite la richiesta `WriteGetObjectResponse`, la quantità effettiva di tempo disponibile potrebbe essere inferiore. Ad esempio, il timeout della funzione Lambda potrebbe essere inferiore a 60 secondi. In altri casi, il chiamante potrebbe avere timeout più rigorosi. 

Affinché il chiamante originale riceva una risposta diversa dal codice di stato HTTP 500 (Internal Server Error) (Errore interno del server), la chiamata `WriteGetObjectResponse` deve essere completata. Se la funzione Lambda restituisce un risultato, eccezionalmente o in altro modo, prima che l'operazione API `WriteGetObjectResponse` venga richiamata, il chiamante originale riceverà una risposta 500 (Internal Server Error) (Errore interno del server). Le eccezioni generate durante il tempo necessario per completare la risposta comportano risposte troncate al chiamante. Se la funzione Lambda riceve una risposta con codice di stato HTTP 200 (OK) dalla chiamata API `WriteGetObjectResponse`, il chiamante originale ha inviato la richiesta completa. La risposta della funzione Lambda, indipendentemente dal fatto che un'eccezione sia generata o meno, viene ignorata da S3 Object Lambda.

Quando viene richiamata l'operazione API `WriteGetObjectResponse`, Amazon S3 richiede il token dell'instradamento e della richiesta dal contesto dell'evento. Per ulteriori informazioni, consulta [Formato e utilizzo del contesto degli eventi](olap-event-context.md).

I parametri relativi ai token dell'instradamento e della richiesta sono necessari per collegare la risposta `WriteGetObjectResult` al chiamante originale. Sebbene sia sempre opportuno riprovare le risposte 500 (Internal Server Error) (Errore interno del server), è necessario considerare che il token della richiesta è un token monouso e i successivi tentativi di utilizzo possono comportare risposte con codice di stato 400 (Bad Request) (Richiesta non valida). Anche se la chiamata a `WriteGetObjectResponse` con i token dell'instradamento e della richiesta non ha bisogno di essere effettuata dalla funzione Lambda richiamata, deve essere effettuata da un'identità nello stesso account. La chiamata deve anche essere completata prima che la funzione Lambda finisca l'esecuzione.

## Utilizzo di richieste `HeadObject` in Lambda
<a name="olap-headobject"></a>

Questa sezione presuppone che il punto di accesso Lambda per oggetti sia configurato per richiamare la funzione Lambda per `HeadObject`. Lambda riceverà un payload JSON contenente una chiave chiamata `headObjectContext`. All'interno del contesto, esiste un'unica proprietà chiamata `inputS3Url`, che è un URL prefirmato per il punto di accesso di supporto per `HeadObject`.

L'URL prefirmato includerà le seguenti proprietà, se specificate: 
+ `versionId` (nei parametri della query)
+ `requestPayer` (nell'intestazione `x-amz-request-payer`)
+ `expectedBucketOwner` (nell'intestazione `x-amz-expected-bucket-owner`)

Le altre proprietà non saranno prefirmate e quindi non saranno incluse. Le opzioni non firmate inviate come intestazioni possono essere aggiunte manualmente alla richiesta quando si richiama l'URL prefirmato che si trova nelle intestazioni `userRequest`. Le opzioni di crittografia lato server non sono supportate per `HeadObject`.

Per i parametri URI della sintassi della richiesta, consulta [https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html) nella *Documentazione di riferimento delle API di Amazon Simple Storage Service*.

Il seguente esempio mostra un payload di input Lambda JSON per `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"
}
```

La funzione Lambda dovrebbe restituire un oggetto JSON contenente le intestazioni e i valori che verranno restituiti per la chiamata `HeadObject`.

Il seguente esempio illustra la struttura dell'oggetto JSON della risposta Lambda per `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>
        ...
    };
}
```

L'esempio seguente mostra come utilizzare l'URL prefirmato per compilare la risposta modificando i valori dell'intestazione secondo necessità prima di restituire l'oggetto 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     
        }
```

------

## Utilizzo di richieste `ListObjects` in Lambda
<a name="olap-listobjects"></a>

Questa sezione presuppone che il punto di accesso Lambda per oggetti sia configurato per richiamare la funzione Lambda per `ListObjects`. Lambda riceverà il payload JSON con un nuovo oggetto denominato `listObjectsContext`. `listObjectsContext` contiene un'unica proprietà `inputS3Url`, che è un URL prefirmato per il punto di accesso di supporto per `ListObjects`.

A differenza di `GetObject` e `HeadObject`, l'URL prefirmato includerà le seguenti proprietà, se specificate:
+ Tutti i parametri della query
+ `requestPayer` (nell'intestazione `x-amz-request-payer`) 
+ `expectedBucketOwner` (nell'intestazione `x-amz-expected-bucket-owner`)

Per i parametri URI della sintassi della richiesta, consulta [https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html) nella *Documentazione di riferimento delle API di Amazon Simple Storage Service*.

**Importante**  
Ti consigliamo di utilizzare la versione più recente, [ListObjectsV2](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html), per lo sviluppo di applicazioni. Per la compatibilità con le versioni precedenti, Amazon S3 continua a supportare `ListObjects`.

Il seguente esempio illustra il payload di input Lambda JSON per `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"
}
```

La funzione Lambda deve restituire un oggetto JSON che contenga il codice di stato, l'elenco dei risultati XML o le informazioni di errore che verranno restituite da Lambda per oggetti S3.

Lambda per oggetti S3 non elabora né convalida `listResultXml`, ma lo inoltra al chiamante `ListObjects`. Per `listBucketResult`, Lambda per oggetti S3 si aspetta che determinate proprietà siano di un tipo specifico e genererà eccezioni se non è in grado di analizzarle. `listResultXml` e `listBucketResult` non possono essere specificati contemporaneamente.

L'esempio seguente illustra come utilizzare l'URL prefirmato per richiamare Amazon S3 e utilizzare il risultato per compilare una risposta, incluso il controllo degli errori.

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

------

Il seguente esempio illustra la struttura dell'oggetto JSON della risposta Lambda per `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'
        },  
        ...  
        ],  
    }
}
```

## Utilizzo di richieste `ListObjectsV2` in Lambda
<a name="olap-listobjectsv2"></a>

Questa sezione presuppone che il punto di accesso Lambda per oggetti sia configurato per richiamare la funzione Lambda per `ListObjectsV2`. Lambda riceverà il payload JSON con un nuovo oggetto denominato `listObjectsV2Context`. `listObjectsV2Context` contiene un'unica proprietà `inputS3Url`, che è un URL prefirmato per il punto di accesso di supporto per `ListObjectsV2`.

A differenza di `GetObject` e `HeadObject`, l'URL prefirmato includerà le seguenti proprietà, se specificate: 
+ Tutti i parametri della query
+ `requestPayer` (nell'intestazione `x-amz-request-payer`) 
+ `expectedBucketOwner` (nell'intestazione `x-amz-expected-bucket-owner`)

Per i parametri URI della sintassi della richiesta, consulta [https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html) nella *Documentazione di riferimento delle API di Amazon Simple Storage Service*.

Il seguente esempio illustra il payload di input Lambda JSON per `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" 
}
```

La funzione Lambda deve restituire un oggetto JSON che contenga il codice di stato, l'elenco dei risultati XML o le informazioni di errore che verranno restituite da Lambda per oggetti S3.

Lambda per oggetti S3 non elabora né convalida `listResultXml`, ma lo inoltra al chiamante `ListObjectsV2`. Per `listBucketResult`, Lambda per oggetti S3 si aspetta che determinate proprietà siano di un tipo specifico e genererà eccezioni se non è in grado di analizzarle. `listResultXml` e `listBucketResult` non possono essere specificati contemporaneamente.

L'esempio seguente illustra come utilizzare l'URL prefirmato per richiamare Amazon S3 e utilizzare il risultato per compilare una risposta, incluso il controllo degli errori.

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

------

Il seguente esempio illustra la struttura dell'oggetto JSON della risposta Lambda per `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'  
            },  
        ...  
        ],  
    }  
}
```