web-dev-qa-db-fra.com

Comment télécharger un fichier volumineux via une fonction Azure?

J'explore Azure Functions. Les scénarios que j'ai testés jusqu'à présent fonctionnent très bien.

Je suis en train d'essayer de trouver un moyen de télécharger des fichiers (20 Mo +) via une fonction Azure. 

L'idée est que la fonction Azure vérifie d'abord si l'utilisateur authentifié est autorisé à télécharger le fichier avant de conserver le flux de la demande et de l'enregistrer dans le stockage BLOB.

Voici le code côté client qui crée une StreamContent pour transmettre les octets au serveur: 

using (Stream fileStream = ...)
{
    var streamContent = new StreamContent(fileStream);

    streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    streamContent.Headers.ContentLength = fileStream.Length;
    streamContent.Headers.Add("FileId", fileId);

    var responseMessage = await m_httpClient.PutAsync(<validURI>, streamContent);

    responseMessage.EnsureSuccessStatusCode();

    succeeded = true;
}

Voici le code côté serveur.

[FunctionName("upload-data")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "put")]HttpRequestMessage req, TraceWriter log)
{
    try
    {
         //  Initialize stuff.

         //  Validate authenticated user & privileges.  

         //  Get the content stream of the request and 
         //  save it in the BLOB storage.

         return req.CreateResponse(HttpStatusCode.OK);
    }
    catch (Exception exc)
    {
        return req.CreateResponse(HttpStatusCode.InternalServerError, exc);
    }
}

Je mets un point d'arrêt dès le début de la méthode. Je m'attendais à ce que le point d'arrêt soit atteint juste après que le côté client ait envoyé la demande, quelle que soit la taille du fichier. Cependant, ce n'est pas le cas. 

Je suppose que la fonction Azure tente en quelque sorte d’obtenir tout le contenu du corps de la demande avant d’appeler la méthode. Je pense également que j'envoie un fichier pouvant dépasser la limite de 4 Mo du travail Web sous-jacent, mais je ne voyais aucun moyen de le configurer.

Est-il possible de télécharger un fichier volumineux vers une fonction Azure en le diffusant en streaming? Existe-t-il un moyen de le faire fonctionner?

8
Kzrystof

J'ai trouvé une autre façon de faire les choses. Voici la solution qui fonctionne pour moi.

Lorsqu'un client doit télécharger un fichier, il appelle la fonction Azure pour être authentifié (à l'aide de l'identité fournie par l'infrastructure) et autorisé (il peut s'agir d'une simple vérification ciblée dans un stockage de table, ce qui signifie qu'il est autorisé à le faire telle opération). 

La fonction Azure demandera une signature d'accès partagé pour accéder à un blob spécifique. Le SAS donnera au client l’accès au stockage Blob avec des privilèges d’écriture seule pendant un temps limité (surveillez le décalage de l’horloge sur Azure).

Le client utilisera ensuite le SAS renvoyé pour télécharger le fichier directement sur le stockage d'objets blob. De cette façon, cela évite la communication à long terme avec le client, comme le mentionne Afzaal Ahmad Zeeshan, et réduit encore plus le coût global, car la fonction Azure ne dépend plus de la vitesse de connexion du client.

7
Kzrystof

Vous suivez une mauvaise pratique ici, Kzrystof. Les fonctions Azure ne sont pas conçues pour la communication à long terme avec les périphériques clients. Je ne suis pas sûr de savoir pourquoi quelqu'un pourrait être intéressé à vous guider dans la rédaction d'un programme permettant de gérer la fonction Azure et de le forcer à faire ce à quoi il n'est pas destiné. 

Des fonctions volumineuses et de longue durée peuvent causer des problèmes de délai d'attente imprévus.

Maintenant, imaginez que vous ayez une bonne connexion Internet, mais que les utilisateurs ne le soient pas. Il y a plusieurs autres problèmes que vous devez prendre en compte avant toute chose. Et ceci est un extrait de la documentation officielle, https://docs.Microsoft.com/en-us/Azure/azure-functions/functions-best-practices

Si je devais concevoir cette application, j'utiliserais App Service → Stockage Azure → Fonctions Azure. Ce serait le flux de travail de l'architecture de mon application.

Dans l'approche de conception, mes applications traitaient ces informations à tour de rôle, tel qu'App Service pourrait s'occuper du téléchargement des images, et je peux alors spécifier si l'utilisateur peut télécharger ou non. ASP.NET Core, ou tout autre langage ou framework, peut être utilisé pour développer cette partie de l'application Web. Vous savez qu'il peut être facilement modifié pour prendre en charge le téléchargement de fichiers d'une taille maximale de 20 Mo.

Pourquoi je vous ai demandé de tordre le design? Vous avez eu une fonction à blob, et je suggère un blob à la fonction, parce que, 

Les fonctions doivent être sans état et idempotentes si possible. Associez toutes les informations d'état requises à vos données. Par exemple, une commande en cours de traitement aurait probablement un membre associé. Une fonction peut traiter un ordre en fonction de cet état tant que la fonction elle-même reste sans état.

Les fonctions elles-mêmes doivent être sans état, ce qui signifie qu'elles ne doivent contenir aucune information à ce sujet. Pour résoudre ce problème, vous aurez besoin d'un autre middleware (ou frontware) pour communiquer avec les serveurs Identity. C'est pourquoi je suggère de: utilisez App Service ici car il peut contenir les informations nécessaires pour authentifier les utilisateurs, puis Blob et enfin, Fonction, si nécessaire.

Ensuite, une fois qu'il est sorti de là, dans le stockage Azure, je peux alors avoir les WebHooks, ou les déclencheurs directs de stockage de blob, qui prennent en charge la délégation à partir de là et traitent l'image dans la fonction Azure - si la fonction l'exige. plus. Examinez comment un déclencheur Blob Storage peut être utilisé pour démarrer une fonction à différentes fins, https://docs.Microsoft.com/en-us/Azure/azure-functions/functions-create-storage-blob- fonction déclenchée .

4

Dès que vous définissez l'en-tête ContentLength, vous ne le diffusez plus. Vous devez utiliser la classe PushStreamContent et écrire dans le flux par morceaux.

Je ne sais pas si vous pourrez toujours accéder à ce flux côté serveur en tant que morceaux. Il est possible que quelque chose dans le pipeline Azure Functions mette en tampon les flux avant de le servir à la fonction.

1
Darrel Miller