Text/Tao Gang
Gérer les téléchargements de fichiers volumineux dans les applications Web a toujours été notoirement difficile, donc pour la plupart des sites, le malheur s'abat sur l'utilisateur si son téléchargement est interrompu. Mais nous n'avons pas besoin de le faire maintenant, car vous pouvez rendre votre application ASP.NET capable de prendre en charge les téléchargements pouvant être repris (continués) de fichiers volumineux. À l'aide de la méthode fournie dans cet article, vous pouvez suivre le processus de téléchargement afin de pouvoir gérer les fichiers créés dynamiquement - et ce, sans avoir besoin de bibliothèques de liens dynamiques ISAPI à l'ancienne et de code C++ non géré.
Il est plus simple de fournir un service permettant aux clients de télécharger des fichiers à partir d'Internet, n'est-ce pas ? Copiez simplement le fichier téléchargeable dans le répertoire de votre application Web, publiez le lien et laissez IIS faire tout le travail associé. Cependant, le service de fichiers ne devrait pas être plus qu'un casse-tête, vous ne voulez pas que le monde entier ait accès à vos données, vous ne voulez pas que votre serveur soit encombré de centaines de fichiers statiques, vous ne le faites pas. Je ne veux même pas télécharger des fichiers temporaires - Ces fichiers ne sont créés que pendant les périodes d'inactivité après le début du téléchargement par le client.
Malheureusement, il n'est pas possible d'obtenir ces effets en utilisant la réponse par défaut d'IIS aux demandes de téléchargement. Ainsi, en général, pour prendre le contrôle du processus de téléchargement, les développeurs doivent créer un lien vers une page .aspx personnalisée où ils vérifient les informations d'identification de l'utilisateur, créent un fichier téléchargeable et utilisent le code suivant pour que le fichier soit transmis au client :
Response.WriteFile
Response.End()
Et c’est là que surgit le vrai problème.
Quel est le problème ?
La méthode WriteFile semble parfaite, elle fait circuler les données binaires du fichier vers le client. Mais ce que nous ne savions pas jusqu'à récemment, c'est que la méthode WriteFile est notoirement gourmande en mémoire, chargeant l'intégralité du fichier dans la RAM du serveur pour le servir (en fait, elle prend deux fois la taille du fichier). Pour les fichiers volumineux, cela peut entraîner des problèmes de mémoire de service et éventuellement une duplication des processus ASP.NET. Mais en juin 2004, Microsoft a publié un correctif qui a résolu le problème. Ce correctif fait désormais partie du Service Pack .NET Framework 1.1 (SP1).
Ce correctif introduit la méthode TransmitFile, qui lit un fichier disque dans une mémoire tampon plus petite, puis commence le transfert du fichier. Bien que cette solution résolve les problèmes de mémoire et de boucle, elle reste insatisfaisante. Vous n'avez aucun contrôle sur le cycle de vie de la réponse. Vous n'avez aucun moyen de savoir si le téléchargement s'est terminé correctement, vous n'avez aucun moyen de savoir si le téléchargement a été interrompu et (si vous avez créé des fichiers temporaires) vous n'avez aucun moyen de savoir si et quand vous devez supprimer les fichiers. Pour aggraver les choses, si le téléchargement échoue, la méthode TransmitFile commence le téléchargement à partir du début du fichier que le client essaie ensuite.
Une solution possible, la mise en œuvre d'un service de transfert intelligent en arrière-plan (BITS), n'est pas réalisable pour la plupart des sites car elle irait à l'encontre de l'objectif consistant à maintenir l'indépendance du navigateur client et du système d'exploitation.
La base d'une solution satisfaisante provient de la première tentative de Microsoft pour résoudre le problème de confusion de mémoire provoqué par WriteFile (voir l'article 812406 de la base de connaissances). Cet article démontrait un processus intelligent de téléchargement de données en bloc qui lit les données à partir d'un flux de fichiers. Avant que le serveur n'envoie le bloc d'octets au client, il utilise la propriété Response.IsClientConnected pour vérifier si le client est toujours connecté. Si la connexion est toujours ouverte, elle continue d'envoyer des octets de flux, sinon elle s'arrête pour empêcher le serveur d'envoyer des données inutiles.
C'est l'approche que nous adoptons, notamment lors du téléchargement de fichiers temporaires. Dans le cas où IsClientConnected renvoie False, vous savez que le processus de téléchargement a été interrompu et vous devez enregistrer le fichier sinon, lorsque le processus se termine avec succès, vous supprimez le fichier temporaire ; De plus, pour reprendre un téléchargement interrompu, il vous suffit de démarrer le téléchargement à partir du point où la connexion client a échoué lors de la dernière tentative de téléchargement.
Prise en charge du protocole HTTP et des informations d'en-tête (Header)
La prise en charge du protocole HTTP peut être utilisée pour gérer les informations d'en-tête pour les téléchargements interrompus. En utilisant un petit nombre d'en-têtes HTTP, vous pouvez améliorer votre processus de téléchargement pour vous conformer pleinement à la spécification du protocole HTTP. Cette spécification, ainsi que les plages, fournissent toutes les informations nécessaires pour reprendre un téléchargement interrompu.
Voici comment cela fonctionne. Premièrement, si le serveur prend en charge les téléchargements avec reprise côté client, il envoie l'en-tête Accept-Ranges dans la réponse initiale. Le serveur envoie également un en-tête de balise d'entité (ETag), qui contient une chaîne d'identification unique.
Le code ci-dessous montre certains des en-têtes que IIS envoie au client en réponse à une demande de téléchargement initiale, qui transmet les détails du fichier demandé au client.
HTTP/1.1 200 OK
Connexion : fermer
Date : mardi 19 octobre 2004 15:11:23 GMT
Plages acceptées : octets
Dernière modification : dimanche 26 septembre 2004 15:52:45 GMT
ETag : "47febb2cfd76c41:2062"
Cache-Control : privé
Type de contenu : application/x-zip-compressé
Content-Length : 2844011
Après avoir reçu ces informations d'en-tête, si le téléchargement est interrompu, le navigateur IE renverra la valeur Etag et les informations d'en-tête Range au serveur lors des demandes de téléchargement ultérieures. Le code ci-dessous montre certains des en-têtes qu'IE envoie au serveur lors de la tentative de reprise d'un téléchargement interrompu.
GET
Ces en-têtes indiquent qu'IE a mis en cache la balise d'entité fournie par IIS et l'a renvoyée au serveur dans l'en-tête If-Range. C'est un moyen de garantir que le téléchargement reprend exactement à partir du même fichier. Malheureusement, tous les navigateurs ne fonctionnent pas de la même manière. Les autres en-têtes HTTP envoyés par le client pour vérifier le fichier peuvent être If-Match, If-Unmodified-Since ou Unless-Modified-Since. Évidemment, la spécification n'est pas explicite sur les en-têtes que le logiciel client doit prendre en charge, ni sur les en-têtes qui doivent être utilisés. Par conséquent, certains clients n'utilisent pas du tout les informations d'en-tête, tandis qu'IE utilise uniquement If-Range et Unless-Modified-Since. Vous feriez mieux de vérifier ces informations avec le code. En adoptant cette approche, votre application peut se conformer à la spécification HTTP à un niveau très élevé et fonctionner avec une variété de navigateurs. L'en-tête Range spécifie la plage d'octets demandée - dans ce cas, il s'agit du point de départ à partir duquel le serveur doit reprendre le flux de fichiers.
Lorsque IIS reçoit une demande de type de téléchargement de reprise, il renvoie une réponse contenant les informations d'en-tête suivantes :
HTTP/1.1 206 Contenu partiel
Plage de contenu : octets 822603-2844010/2844011
Plages acceptées : octets
Dernière modification : dimanche 26 septembre 2004 15:52:45 GMT
ETag : "47febb2cfd76c41:2062"
Cache-Control : privé
Type de contenu : application/x-zip-compressé
Longueur du contenu : 2021408
Veuillez noter que le code ci-dessus a une réponse HTTP légèrement différente de celle de la demande de téléchargement d'origine : la demande de reprise du téléchargement est 206 alors que la demande de téléchargement d'origine était de 200. Cela indique que ce qui est transmis sur le réseau est un fichier partiel. Cette fois, l'en-tête Content-Range indique le nombre exact et l'emplacement des octets transmis.
IE est très pointilleux sur ces informations d'en-tête. Si la réponse initiale ne contient pas les informations d’en-tête Etag, IE ne tentera jamais de reprendre le téléchargement. Les autres clients que j'ai testés n'utilisent pas l'en-tête ETag, ils s'appuient simplement sur le nom du fichier, la portée de la demande et utilisent l'en-tête Last-Modified s'ils tentent de valider le fichier.
Une compréhension approfondie du protocole HTTP
Les informations d'en-tête présentées dans la section précédente sont suffisantes pour faire fonctionner la solution de reprise des téléchargements, mais elles ne couvrent pas complètement la spécification HTTP.
L'en-tête Range peut demander plusieurs plages en une seule requête, une fonctionnalité appelée « plages en plusieurs parties ». À ne pas confondre avec le téléchargement segmenté, presque tous les outils de téléchargement utilisent le téléchargement segmenté pour augmenter les vitesses de téléchargement. Ces outils prétendent augmenter les vitesses de téléchargement en ouvrant deux ou plusieurs connexions simultanées, chacune demandant une gamme différente de fichiers.
L'idée des plages en plusieurs parties n'ouvre pas plusieurs connexions, mais elle permet au logiciel client de demander les dix premiers et dix derniers octets d'un fichier en un seul cycle requête/réponse.
Pour être honnête, je n’ai jamais trouvé de logiciel utilisant cette fonctionnalité. Mais je refuse d'écrire "ce n'est pas entièrement conforme à HTTP" dans la déclaration de code. Omettre cette fonctionnalité violerait définitivement la loi de Murphy. Quoi qu'il en soit, des plages en plusieurs parties sont utilisées dans les transmissions par courrier électronique pour séparer les informations d'en-tête, le texte brut et les pièces jointes.
Exemple de code
Nous savons comment le client et le serveur échangent des informations d'en-tête pour garantir la reprise des téléchargements. En combinant ces connaissances avec l'idée de streaming de blocs de fichiers, vous pouvez ajouter des fonctionnalités de gestion de téléchargement fiables à vos applications ASP.NET.
La façon de prendre le contrôle du processus de téléchargement consiste à intercepter la demande de téléchargement du client, à lire les informations d'en-tête et à répondre de manière appropriée. Avant .NET, vous deviez écrire une application ISAPI (Internet Server API) pour implémenter cette fonctionnalité, mais le composant .NET Framework fournit une interface IHttpHandler qui, lorsqu'elle est implémentée dans une classe, vous permet de le faire en utilisant uniquement le code .NET Intercept. et traiter les demandes. Cela signifie que votre application a un contrôle total et une réactivité totale sur le processus de téléchargement et n'implique ni n'utilise jamais les fonctions automatisées d'IIS.
L'exemple de code inclut une classe HttpHandler personnalisée (ZIPHandler) dans le fichier HttpHandler.vb. ZipHandler implémente l'interface IhttpHandler et gère les requêtes pour tous les fichiers .zip.
Afin de tester l'exemple de code, vous devez créer un nouveau répertoire virtuel dans IIS et y copier les fichiers source. Créez un fichier appelé download.zip dans ce répertoire (veuillez noter que IIS et ASP.NET ne peuvent pas gérer les téléchargements de plus de 2 Go, alors assurez-vous que votre fichier ne dépasse pas cette limite). Configurez votre répertoire virtuel IIS pour mapper l'extension .zip via aspnet_isapi.dll.
Classe HttpHandler : une fois que ZIPHandler
a mappé l'extension .zip dans ASP.NET, chaque fois que le client demande un fichier .zip au serveur, IIS appelle la méthode ProcessRequest de la classe ZipHandler (voir le code de téléchargement).
La méthode ProcessRequest crée d'abord une instance de la classe FileInformation personnalisée (voir le code de téléchargement), qui encapsule l'état du téléchargement (par exemple en cours, interrompu, etc.). L’exemple code en dur le chemin d’accès à l’exemple de fichier download.zip dans le code. Si vous appliquez ce code à votre propre application, vous devrez le modifier pour ouvrir le fichier demandé.
' Utilisez objRequest pour détecter quel fichier a été demandé et utilisez le fichier pour ouvrir objFile.
' Par exemple objFile = New Download.FileInformation(<nom complet du fichier>)
objFile = Nouveau Download.FileInformation( _
objContext.Server.MapPath("~/download.zip"))
Ensuite, le programme exécute la requête en utilisant les en-têtes HTTP décrits (si les en-têtes ont été fournis dans la requête). J'ai prié pour la première fois sous le soleil. Si un contrôle de validation échoue, la réponse est immédiatement terminée et la valeur StatusCode appropriée est envoyée.
Si ce n'est pas le cas, objRequest.HttpMethod.Equals(HTTP_METHOD_GET) ou non
objRequest.HttpMethod.Equals(HTTP_METHOD_HEAD) Puis
' Actuellement, seules les méthodes GET et HEAD sont prises en charge. objResponse.StatusCode = 501 ' Non exécuté
Sinon, si ce n'est pas objFile.Exists, alors
' Le fichier demandé est introuvable objResponse.StatusCode = 404 ' Introuvable
ElseIf objFile.Length > Int32.MaxValue Alors
'Le fichier est trop volumineux objResponse.StatusCode = 413 'L'entité de requête est trop volumineuse
ElseIf Not ParseRequestHeaderRange(objRequest, alRequestedRangesBegin, alRequestedRangesend, _
objFile.Length, bIsRangeRequest) Puis
' La requête Range contient des entités inutiles objResponse.StatusCode = 400 ' Requête inutile
ElseIf Not CheckIfModifiedSince(objRequest,objFile) Alors
'L'entité n'a pas été modifiée objResponse.StatusCode = 304 'L'entité n'a pas été modifiée
ElseIf Not CheckIfUnmodifiedSince(objRequest,objFile) Alors
' L'entité a été modifiée depuis la dernière date demandée objResponse.StatusCode = 412 ' Échec du prétraitement
ElseIf Not CheckIfMatch(objRequest, objFile) Then
' L'entité ne correspond pas à la requête objResponse.StatusCode = 412 ' Échec du prétraitement
ElseIf Not CheckIfNoneMatch(objRequest, objResponse,objFile) Then
' L'entité correspond à la demande sans correspondance.
'Le code de réponse se trouve dans la fonction CheckIfNoneMatch
Autre
'Vérification préliminaire réussie
La fonction ParseRequestHeaderRange dans ces vérifications préliminaires (voir code de téléchargement) vérifie si le client a demandé une plage de fichiers (ce qui signifie un téléchargement partiel). Si la plage demandée n'est pas valide (une plage non valide est une valeur de plage qui dépasse la taille du fichier ou contient un nombre déraisonnable), cette méthode définit bIsRangeRequest sur True. Si une plage est demandée, la méthode CheckIfRange vérifie les informations d'en-tête IfRange.
Si la plage demandée est valide, le code calcule la taille du message de réponse. Si le client a demandé plusieurs plages, la valeur de taille de réponse inclura la valeur de longueur d’en-tête en plusieurs parties.
Si une valeur d'en-tête envoyée ne peut pas être déterminée, le programme traitera la demande de téléchargement comme une demande initiale plutôt que comme un téléchargement partiel, en envoyant un nouveau flux de téléchargement en commençant par le haut du fichier.
Si bIsRangeRequest AndAlso CheckIfRange(objRequest, objFile) Alors
'Il s'agit d'une requête de plage' Si le tableau Range contient plusieurs entités, il s'agit également d'une requête de plage en plusieurs parties bMultipart = CBool(alRequestedRangesBegin.GetUpperBound(0)>0)
' Accédez à chaque plage pour obtenir la longueur totale de la réponse. For iLoop = alRequestedRangesBegin.GetLowerBound(0) To alRequestedRangesBegin.GetUpperBound(0)
'La longueur du contenu (dans cette plage)
iResponseContentLength += Convert.ToInt32(alRequestedRangesend( _
iLoop) - alRequestedRangesBegin(iLoop)) + 1
Si bMultipart Alors
' S'il s'agit d'une demande de plage en plusieurs parties, calculez la longueur des informations d'en-tête intermédiaire à envoyer iResponseContentLength += MULTIPART_BOUNDARY.Length
iResponseContentLength += objFile.ContentType.Length
iResponseContentLength += alRequestedRangesBegin(iLoop).ToString.Length
iResponseContentLength += alRequestedRangesend(iLoop).ToString.Length
iResponseContentLength += objFile.Length.ToString.Length
' 49 est la longueur des sauts de ligne et des autres caractères nécessaires dans les téléchargements en plusieurs parties iResponseContentLength += 49
Fin si
Suivant iLoop
Si bMultipart Alors
' S'il s'agit d'une demande de plage en plusieurs parties,
' Il faut également calculer la longueur du dernier en-tête intermédiaire qui sera envoyé iResponseContentLength +=MULTIPART_BOUNDARY.Length
' 8 est la longueur du tiret et de la nouvelle ligne iResponseContentLength += 8
Autre
' Il ne s'agit pas d'un téléchargement en plusieurs parties, nous devons donc spécifier la plage de réponse de l'en-tête HTTP initial objResponse.AppendHeader( HTTP_HEADER_CONTENT_RANGE, "bytes " & _
alRequestedRangesBegin(0).ToString & "-" & _
alRequestedRangesend(0).ToString & "/" & _
objFile.Length.ToString)
'Fin si
' Plage de réponse objResponse.StatusCode = 206 ' Réponse partielle Sinon
' Il ne s'agit pas d'une demande de portée, ou l'ID d'entité de portée demandé ne correspond pas à l'ID d'entité actuel.
'Alors démarrez un nouveau téléchargement' indique que la taille de la partie complétée du fichier est égale à la longueur du contenu iResponseContentLength =Convert.ToInt32(objFile.Length)
'Retour à l'état normal OK objResponse.StatusCode = 200
Fin si
' Ensuite, le serveur doit envoyer plusieurs en-têtes de réponse importants, tels que la longueur du contenu, l'Etag et le type de contenu du fichier :
' Écrivez la longueur du contenu dans la réponse objResponse.AppendHeader( HTTP_HEADER_CONTENT_LENGTH,iResponseContentLength.ToString)
' Écrivez la date de la dernière modification dans la réponse objResponse.AppendHeader( HTTP_HEADER_LAST_MODIFIED,objFile.LastWriteTimeUTC.ToString("r"))
' Dites au logiciel client que nous avons accepté la demande de plage objResponse.AppendHeader( HTTP_HEADER_ACCEPT_RANGES,HTTP_HEADER_ACCEPT_RANGES_BYTES)
' Écrivez la balise d'entité du fichier dans la réponse (entre guillemets)
objResponse.AppendHeader(HTTP_HEADER_ENTITY_TAG, """" & objFile.EntityTag & """")
'Écrire le type de contenu dans réponseSi bMultipart Alors
'Les messages en plusieurs parties ont ce type spécial' Dans l'exemple, le type MIME réel du fichier est écrit ultérieurement dans la réponse objResponse.ContentType = MULTIPART_CONTENTTYPE
Autre
'Le type de contenu de fichier appartenant à un seul message partiel objResponse.ContentType = objFile.ContentType
Fin si
Tout ce dont vous avez besoin pour le téléchargement est prêt et vous pouvez commencer à télécharger des fichiers. Vous utiliserez un objet FileStream pour lire des morceaux d'octets à partir d'un fichier. Définissez la propriété State de l'instance FileInformation objFile sur fsDownloadInProgress. Tant que le client reste connecté, le serveur lit des morceaux d'octets du fichier et les envoie au client. Pour les téléchargements en plusieurs parties, ce code envoie des informations d'en-tête spécifiques. Si le client se déconnecte, le serveur définit l'état du fichier sur fsDownloadBroken. Si le serveur termine l'envoi de la plage demandée, il définit le statut sur fsDownloadFinished (voir le code de téléchargement).
Classe auxiliaire FileInformation
Dans la section ZIPHandler, vous constaterez que FileInformation est une classe auxiliaire qui encapsule les informations sur l'état du téléchargement (telles que téléchargement, interruption, etc.).
Pour créer une instance de FileInformation, vous devez transmettre le chemin d'accès au fichier demandé au constructeur de la classe :
Public Sub New(ByVal sPath As String)
m_objFile = Nouveau System.IO.FileInfo (sPath)
End Sub
FileInformation utilise l'objet System.IO.FileInfo pour obtenir des informations sur le fichier, qui sont exposées en tant que propriétés de l'objet (telles que l'existence du fichier, le nom complet du fichier, sa taille, etc.). Cette classe expose également une énumération DownloadState, qui décrit les différents états de la demande de téléchargement :
Enum DownloadState
' Effacer : aucun processus de téléchargement, le fichier peut conserver fsClear = 1
'Verrouillé : les fichiers créés dynamiquement ne peuvent pas être modifiés fsLocked = 2
'En cours : le fichier est verrouillé et le processus de téléchargement est en cours fsDownloadInProgress = 6
'Cassé : Le fichier est verrouillé, le processus de téléchargement était en cours, mais a été annulé fsDownloadBroken = 10
' Terminé : le fichier est verrouillé et le processus de téléchargement est terminé fsDownloadFinished = 18
End Enum
FileInformation fournit également la valeur de l'attribut EntityTag. Cette valeur est codée en dur dans l'exemple de code car celui-ci n'utilise qu'un seul fichier à télécharger et ce fichier ne sera pas modifié, mais pour une application réelle, vous fournirez plusieurs fichiers, même dynamiquement. Pour créer des fichiers, votre code doit fournir un valeur EntityTag unique pour chaque fichier. De plus, cette valeur doit changer à chaque fois que le fichier est modifié ou modifié. Cela permet au logiciel client de vérifier que les morceaux d'octets qu'ils ont téléchargés sont toujours à jour. Voici la partie de l'exemple de code qui renvoie la valeur EntityTag codée en dur :
Public ReadOnly Property EntityTag() As String
' EntityTag est utilisé pour la réponse initiale (200) au client et pour les demandes de récupération du client Get
'Créez une chaîne unique pour le fichier.
' Notez que tant que le fichier ne change pas, le code unique doit être conservé.
' Cependant, si le fichier change ou est modifié, ce code doit changer.
Renvoie "MonExampleFileID"
Fin Obtenir
Propriété End
Un EntityTag simple et généralement suffisamment sûr peut être constitué du nom du fichier et de la date à laquelle le fichier a été modifié pour la dernière fois. Quelle que soit la méthode que vous utilisez, vous devez vous assurer que cette valeur est véritablement unique et ne peut pas être confondue avec l'EntityTag d'autres fichiers. Je souhaite nommer dynamiquement les fichiers créés dans mon application par client, client et index de code postal, et stocker le GUID utilisé comme EntityTag dans la base de données.
La classe ZipFileHandler lit et définit la propriété publique State. Une fois le téléchargement terminé, il définit l'état sur fsDownloadFinished. À ce stade, vous pouvez supprimer les fichiers temporaires. Ici, vous devez généralement appeler la méthode Save pour conserver l'état.
État de propriété publique () en tant que DownloadState
Obtenir
Retourner m_nState
Fin Obtenir
Définir (ByVal nState comme DownloadState)
m_nÉtat = nÉtat
' Action facultative : vous pouvez supprimer le fichier automatiquement à ce moment.
' Si le statut est défini sur Terminé, vous n'avez plus besoin de ce fichier.
' Si nState = DownloadState.fsDownloadFinished Alors
'Clair()
'Autre
'Sauvegarder()
'Fin si
Sauvegarder()
Ensemble de fin
End Property
ZipFileHandler doit appeler la méthode Save à chaque fois que l'état du fichier change pour enregistrer l'état du fichier afin qu'il puisse être affiché à l'utilisateur ultérieurement. Vous pouvez également l'utiliser pour enregistrer l'EntityTag que vous avez créé vous-même. Veuillez ne pas enregistrer l'état du fichier et la valeur EntityTag dans l'application, la session ou le cache : vous devez enregistrer les informations tout au long du cycle de vie de tous ces objets.
PrivateSubSave()
'Enregistrez l'état de téléchargement du fichier dans la base de données ou dans le fichier XML.
' Bien entendu, si vous ne créez pas le fichier de manière dynamique, vous n'avez pas besoin de sauvegarder cet état.
End Sub
Comme mentionné précédemment, l'exemple de code gère uniquement un fichier existant (download.zip), mais vous pouvez améliorer davantage ce programme pour créer le fichier demandé si nécessaire.
Lors du test de l'exemple de code, votre système local ou votre réseau local peut être trop rapide pour interrompre le processus de téléchargement, je vous recommande donc d'utiliser une connexion LAN lente (la réduction de la bande passante du site dans IIS est une méthode de simulation) ou de mettre le serveur sur l'Internet.
Le téléchargement de fichiers sur le client reste un combat. Un serveur de cache Web incorrect ou mal configuré exploité par un FAI peut entraîner l'échec des téléchargements de fichiers volumineux, notamment de mauvaises performances de téléchargement ou une interruption prématurée de la session. Si la taille du fichier dépasse 255 Mo, vous devez encourager les clients à utiliser un logiciel de gestion de téléchargement tiers, bien que certains navigateurs récents intègrent des gestionnaires de téléchargement de base.
Si vous souhaitez étendre davantage l'exemple de code, il peut être utile de consulter la spécification HTTP. Vous pouvez établir des sommes de contrôle MD5 pour les téléchargements, en les ajoutant à l'aide de l'en-tête Content-MD5 pour fournir un moyen de vérifier l'intégrité des fichiers téléchargés. L'exemple de code n'implique pas d'autres méthodes HTTP à l'exception de GET et HEAD.