API REST - fichier (c'est à dire des images) traitement - les meilleures pratiques
Nous développons serveur avec l'API REST, qui accepte et réponses avec JSON. Le problème est, si vous avez besoin de télécharger des images à partir du serveur vers le client.
Remarque aussi que je parle de cas d'utilisation, où l'entité (utilisateur) peut avoir des fichiers (carPhoto, licensePhoto) et ont aussi d'autres propriétés (nom, prénom, email...), mais lorsque vous créez un nouvel utilisateur, vous n'avez pas envoyer ces images, elles sont ajoutés après le processus d'enregistrement.
Les solutions je suis au courant, mais chacun d'entre eux ont quelques défauts
1. Utilisation multipart/form-data au lieu de JSON
bonne : requêtes POST et PUT sont aussi Reposant que possible, ils peuvent contenir du texte des entrées en collaboration avec le fichier.
contre : Il n'est pas du JSON en plus, ce qui est beaucoup plus facile à tester, déboguer etc. comparer à multipart/form-data
2. Permettre de mettre à jour des fichiers séparés
Requête POST pour la création d'un nouvel utilisateur ne permet pas d'ajouter des images (ce qui est normal dans notre cas d'utilisation comment je l'ai dit au début), en téléchargeant des images se fait par requête PUT que multipart/form-data par exemple /users/4/carPhoto
bonne : Tout (sauf le téléchargement du fichier lui-même) reste en JSON, il est facile de tester et de déboguer (vous pouvez vous connecter remplir JSON demandes sans avoir peur de leur longueur)
contre : Il n'est pas intuitif, vous ne pouvez pas POSTER ou METTRE toutes les variables de l'entité à la fois et aussi cette adresse /users/4/carPhoto
peut être considéré comme une collection (de série de cas d'utilisation de l'API REST ressemble à ceci /users/4/shipments
). Habituellement, vous ne pouvez pas (et ne veux pas) GET/PUT chaque variable de l'entité, par exemple les utilisateurs/4/nom . Vous pouvez obtenir le nom avec les OBTENIR et de les modifier à METTRE dans utilisateurs/4. Si il y a quelque chose après la id, il est généralement une autre collection, comme les utilisateurs/4/examens
3. Utilisation Base64
L'envoyer en JSON mais encoder les fichiers avec Base64.
bonne : la Même que pour la première solution, il est plus Reposant de service possible.
contre : une Fois de plus, les tests et le débogage est bien pire (le corps peut avoir des méga-octets de données), il y a augmentation de la taille et aussi en temps de traitement à la fois client et serveur
Je tiens vraiment à utiliser la solution pas. 2, mais elle a ses inconvénients... quelqu'un peut me donner une meilleure idée de "quelle est la meilleure solution?
Mon but est d'avoir des services RESTful avec autant de normes que possible, alors que je veux le garder aussi simple que possible.
- Vous pouvez également trouver cela utile: stackoverflow.com/questions/4083702/...
- Je sais que ce sujet est vieux, mais nous avons dû faire face à ce problème récemment. La meilleure approche que nous avons obtenu est semblable à la vôtre numéro 2. Nous télécharger des fichiers directement à l'API et fixez ensuite ces fichiers dans le modèle. Avec ce scénario, vous pouvez créer des images de téléchargement avant, après ou à la même page que le formulaire n'a pas vraiment d'importance. Bonne discussion!
- oui, exactement, je l'ai décrit dans l'une réponse qui j'ai récemment accepté
- Merci pour cette question.
- "aussi cette adresse /utilisateurs/4/carPhoto peut être considéré comme une collection" – non, il ne ressemble pas à une collection et ne serait pas nécessairement être considérés comme un seul. C'est très bien d'avoir une relation à une ressource qui n'est pas une collection, mais seule ressource.
- Pour l'option 1 et 3 il y a un autre "con": Si vous envoyez plus d'une image dans un formulaire, le transfert de données peut être très large et dépasse fichier des restrictions de téléchargement sur votre serveur. La meilleure option est de 2
- bon point
Vous devez vous connecter pour publier un commentaire.
OP ici (je suis de répondre à cette question après deux ans, le post de Daniel Cerecedo n'était pas mauvais à la fois, mais les services web sont un développement très rapide)
Après trois ans de développement de logiciels (avec l'accent également sur l'architecture logicielle, gestion de projet et microservice architecture) j'ai certainement choisir la deuxième voie (mais avec un point de terminaison) comme le meilleur.
Si vous avez un spécial de point de terminaison pour les images, il vous donne beaucoup plus de pouvoir sur le traitement de ces images.
Nous avons la même API REST (Node.js) pour les deux - applications mobiles (iOS/android) et frontend (à l'aide de Réagir). C'est 2017, par conséquent, vous ne voulez pas stocker les images localement, vous voulez les télécharger à certaines de stockage en nuage (cloud Google, s3, cloudinary, ...), par conséquent, vous voulez de la gestion générale sur eux.
Notre flux typique est, que dès que vous sélectionnez une image, il commence à télécharger sur le fond (généralement de POST sur /images endpoint), vous retourner l'ID après le téléchargement. C'est vraiment convivial, que l'utilisateur de choisir une image et puis généralement, procéder à d'autres domaines (ex: adresse, nom, ...), donc quand il frappe bouton "envoyer", l'image est généralement déjà téléchargé. Il ne fait pas attendre et de regarder l'écran en disant "téléchargement...".
Il en va de même pour l'obtention des images. En particulier grâce à des téléphones mobiles et limitée de données mobiles, vous ne voulez pas envoyer des images d'origine, vous voulez envoyer des images redimensionnées, de sorte qu'ils ne prennent pas beaucoup de bande passante (et pour faire de votre mobile des applications plus rapides, souvent, vous ne voulez pas à la redimensionner à tous, vous voulez que l'image qui s'adapte parfaitement à votre vue). Pour cette raison, de bonnes applications sont en utilisant quelque chose comme cloudinary (ou nous avons notre propre serveur d'image pour la redimensionner).
Aussi, si les données ne sont pas privées, puis que vous renvoyer à l'application/frontend juste l'URL et elle se télécharge à partir de stockage dans le cloud directement, ce qui est énorme économie de la bande passante et le temps de traitement de votre serveur. Dans nos grands apps il y a beaucoup de téra-octets téléchargés chaque mois, vous ne voulez pas manipuler directement sur chacun de vos API REST serveur, qui est axé sur l'opération CRUD. Vous souhaitez gérer qu'à un endroit (notre Imageserver, qui ont de la mise en cache, etc.) ou laissez-les services de cloud gérer tout cela.
Inconvénients : Le seul "contre" qui vous devriez penser "n'est pas assigné à images". L'utilisateur de sélectionner les images et continuer à remplir les autres champs, puis, il dit "non" et de désactiver l'application ou de l'onglet, mais en attendant vous avez téléchargé l'image. Cela signifie que vous avez téléchargé une image qui n'est pas affecté n'importe où.
Il y a plusieurs façons de gérer cela. Le plus simple, c'est "I don't care", qui est pertinente, si cela ne se produit pas très souvent ou vous même avez désir pour stocker chaque image utilisateur de vous envoyer (pour une raison quelconque) et vous ne voulez pas de suppression.
Un autre est facile - vous avez CRON et c'est à dire chaque semaine et que vous supprimez tous les éléments non des images datant de plus d'une semaine.
MemoryStorage
Il y a plusieurs décisions à prendre:
La première sur chemin d'accès aux ressources:
Modèle de l'image en tant que ressource sur son propre:
Imbriquée dans de l'utilisateur (/utilisateur/:id/image): la relation entre l'utilisateur et l'image est faite implicitement
Dans le chemin de la racine (/image):
Le client est tenu responsable pour l'établissement de la relation entre l'image et l'utilisateur, ou;
Si un contexte de sécurité est fournie avec la demande POST utilisée pour créer une image, le serveur peut implicitement d'établir une relation entre l'utilisateur authentifié et l'image.
Insérer l'image dans le cadre de l'utilisateur
La deuxième décision est d'environ comment représenter l'image de la ressource:
Ce serait ma décision piste:
Puis vient la question: Est-il un impact sur les performances sur le choix de la base64 vs multipart?. On pourrait penser que l'échange de données au format multipart devrait être plus efficace. Mais cet article montre comment peu faire les deux représentations diffèrent en termes de taille.
Mon choix Base64:
Votre deuxième solution est probablement la plus correcte. Vous devez utiliser la spécification HTTP et types mime la façon dont ils sont destinés et de télécharger le fichier via
multipart/form-data
. Pour la gestion de la relation, je voudrais utiliser ce processus (en gardant à l'esprit je sais zéro au sujet de vos hypothèses ou de la conception du système):POST
à/users
pour créer l'entité utilisateur.POST
l'image de/images
, faire en sorte de faire revenir unLocation
en-tête à l'endroit où l'image peut être récupéré par la spécification HTTP.PATCH
à/users/carPhoto
et de l'attribuer l'ID de la photo donnée dans leLocation
en-tête de l'étape 2.Il n'y a pas de solution facile. Chaque méthode présente des avantages et des inconvénients . Mais la manière canonique est d'utiliser la première option:
multipart/form-data
. Comme W3 guide de recommandation ditNous ne sommes pas de l'envoi des formulaires,vraiment, mais l'implicite principe s'applique toujours. En utilisant base64 comme une représentation binaire, est erronée parce que vous utilisez le mauvais outil pour atteindre votre objectif, en revanche, la deuxième option forces de votre API clients à faire plus de travail afin de consommer votre service API. Vous devez faire le travail dur dans le serveur dans le but de fournir un outil facile à utiliser l'API. La première option n'est pas facile à déboguer, mais quand vous le faites, il n'a probablement jamais les changements.
À l'aide de
multipart/form-data
vous êtes collé avec le RESTE/http philosophie. Vous pouvez afficher une réponse à une question similaire ici.Une autre option, si le mélange des solutions de rechange, vous pouvez utiliser multipart/form-data mais au lieu d'envoyer chaque valeur distincte, vous pouvez envoyer une valeur nommée charge utile avec le json de la charge utile à l'intérieur. (J'ai essayé cette approche à l'aide de ASP.NET WebAPI 2 et fonctionne très bien).