Wir entwickeln einen Server mit REST-API, der JSON akzeptiert und mit JSON antwortet. Das Problem ist, wenn Sie Bilder vom Client auf den Server hochladen müssen.
Hinweis: und ich spreche auch von einem Anwendungsfall, bei dem die Entität (Benutzer) mehrere Dateien (carPhoto, licensePhoto) und auch andere Eigenschaften (Name, E-Mail ...) haben kann, aber wenn Sie einen neuen Benutzer erstellen, tun Sie dies nicht Senden Sie diese Bilder nicht, sie werden nach dem Registrierungsprozess hinzugefügt.
Die Lösungen sind mir bekannt, aber jede hat einige Mängel
1. Verwenden Sie Multipart / Formulardaten anstelle von JSON
gut : POST- und PUT-Anforderungen sind so RESTful wie möglich, sie können Texteingaben zusammen mit einer Datei enthalten.
Nachteile : Es ist nicht mehr JSON, was viel einfacher zu testen, zu debuggen usw. ist, verglichen mit mehrteiligen / Formulardaten
2. Ermöglichen Sie das Aktualisieren separater Dateien
Die POST-Anforderung zum Erstellen eines neuen Benutzers erlaubt nicht das Hinzufügen von Bildern (was in unserem Anwendungsfall, wie ich zu Beginn sagte, in Ordnung ist). Das Hochladen von Bildern erfolgt per PUT-Anforderung als mehrteilige / Formulardaten zu beispielsweise / users / 4 / carPhoto
gut : Alles (außer dem Hochladen der Datei selbst) bleibt in JSON, es ist einfach zu testen und zu debuggen (Sie können vollständige JSON-Anforderungen protokollieren, ohne Angst vor ihrer Länge zu haben).
Nachteile : Es ist nicht intuitiv, Sie können nicht alle Variablen der Entität gleichzeitig POSTEN oder PUTEN, und auch diese Adresse /users/4/carPhoto
kann eher als Sammlung betrachtet werden (der Standardanwendungsfall für die REST-API sieht so aus /users/4/shipments
). Normalerweise können (und wollen) Sie nicht jede Entitätsvariable GET / PUT, zum Beispiel users / 4 / name. Sie können den Namen mit GET abrufen und mit PUT unter users / 4 ändern. Wenn nach der ID etwas steht, handelt es sich normalerweise um eine andere Sammlung, z. B. users / 4 / reviews
3. Verwenden Sie Base64
Senden Sie es als JSON, aber codieren Sie Dateien mit Base64.
gut : Wie bei der ersten Lösung ist es ein möglichst ruhiger Service.
Nachteile : Erneut ist das Testen und Debuggen viel schlimmer (der Körper kann Megabyte an Daten haben), es gibt eine Zunahme der Größe und auch der Verarbeitungszeit sowohl auf dem Client als auch auf dem Server
Ich würde wirklich gerne Lösung Nr. Verwenden. 2, aber es hat seine Nachteile ... Kann mir jemand einen besseren Einblick in die "Was ist die beste" Lösung geben?
Mein Ziel ist es, RESTful-Services mit möglichst vielen Standards zu haben, während ich es so einfach wie möglich halten möchte.
Antworten:
OP hier (Ich beantworte diese Frage nach zwei Jahren, der Beitrag von Daniel Cerecedo war zu einem Zeitpunkt nicht schlecht, aber die Webdienste entwickeln sich sehr schnell)
Nach drei Jahren Vollzeit-Softwareentwicklung (mit Schwerpunkt auch auf Softwarearchitektur, Projektmanagement und Microservice-Architektur) wähle ich definitiv den zweiten Weg (aber mit einem allgemeinen Endpunkt) als den besten.
Wenn Sie einen speziellen Endpunkt für Bilder haben, haben Sie viel mehr Möglichkeiten, diese Bilder zu verarbeiten.
Wir haben die gleiche REST-API (Node.js) für beide - mobile Apps (iOS / Android) und Frontend (mit React). Dies ist 2017, daher möchten Sie Bilder nicht lokal speichern, sondern in einen Cloud-Speicher (Google Cloud, S3, Cloudinary, ...) hochladen. Daher möchten Sie eine allgemeine Behandlung dieser Bilder.
Unser typischer Ablauf ist, dass sobald Sie ein Bild auswählen, es im Hintergrund hochgeladen wird (normalerweise POST on / images endpoint) und Ihnen nach dem Hochladen die ID zurückgibt. Dies ist sehr benutzerfreundlich, da der Benutzer ein Bild auswählt und dann normalerweise mit einigen anderen Feldern fortfährt (z. B. Adresse, Name, ...). Wenn er also auf die Schaltfläche "Senden" klickt, wird das Bild normalerweise bereits hochgeladen. Er wartet nicht und schaut auf den Bildschirm mit der Aufschrift "Upload ...".
Gleiches gilt für das Abrufen von Bildern. Insbesondere dank Mobiltelefonen und begrenzten mobilen Daten möchten Sie keine Originalbilder senden, sondern Bilder mit geänderter Größe senden, damit diese nicht so viel Bandbreite beanspruchen (und um Ihre mobilen Apps schneller zu machen, möchten Sie dies häufig nicht Um die Größe überhaupt zu ändern, möchten Sie das Bild, das perfekt in Ihre Ansicht passt. Aus diesem Grund verwenden gute Apps so etwas wie Cloudinary (oder wir haben einen eigenen Image-Server zum Ändern der Größe).
Wenn die Daten nicht privat sind, senden Sie sie nur an die App / das Frontend zurück und laden sie direkt aus dem Cloud-Speicher herunter. Dies spart Bandbreite und Verarbeitungszeit für Ihren Server erheblich. In unseren größeren Apps werden jeden Monat viele Terabyte heruntergeladen. Sie möchten dies nicht direkt auf jedem Ihrer REST-API-Server erledigen, der sich auf den CRUD-Betrieb konzentriert. Sie möchten dies an einem Ort erledigen (unser Imageserver mit Caching usw.) oder Cloud-Services alles erledigen lassen.
Nachteile: Die einzigen "Nachteile", an die Sie denken sollten, sind "nicht zugewiesene Bilder". Der Benutzer wählt Bilder aus und füllt andere Felder aus. Dann sagt er "nah" und deaktiviert die App oder den Tab. In der Zwischenzeit haben Sie das Bild jedoch erfolgreich hochgeladen. Dies bedeutet, dass Sie ein Bild hochgeladen haben, das nirgendwo zugewiesen ist.
Es gibt verschiedene Möglichkeiten, damit umzugehen. Am einfachsten ist "Es ist mir egal", was relevant ist, wenn dies nicht sehr oft vorkommt oder Sie sogar den Wunsch haben, jedes Bild zu speichern, das Ihnen der Benutzer sendet (aus irgendeinem Grund), und Sie möchten keines Streichung.
Ein anderes ist auch einfach - Sie haben CRON und dh jede Woche und Sie löschen alle nicht zugewiesenen Bilder, die älter als eine Woche sind.
quelle
Es sind mehrere Entscheidungen zu treffen :
Der erste über Ressourcenpfad :
Modellieren Sie das Bild als eigenständige Ressource:
Im Benutzer verschachtelt (/ user /: id / image): Die Beziehung zwischen dem Benutzer und dem Bild wird implizit hergestellt
Im Stammpfad (/ image):
Der Kunde ist dafür verantwortlich, die Beziehung zwischen dem Bild und dem Benutzer herzustellen, oder;
Wenn ein Sicherheitskontext mit der POST-Anforderung bereitgestellt wird, die zum Erstellen eines Images verwendet wird, kann der Server implizit eine Beziehung zwischen dem authentifizierten Benutzer und dem Image herstellen.
Betten Sie das Bild als Teil des Benutzers ein
Die zweite Entscheidung betrifft die Darstellung der Bildressource :
Dies wäre meine Entscheidung:
Dann kommt die Frage: Gibt es irgendwelche Auswirkungen auf die Leistung bei der Auswahl von base64 gegenüber multipart? . Wir könnten denken, dass der Datenaustausch im mehrteiligen Format effizienter sein sollte. Aber dieser Artikel zeigt , wie wenig die beiden Darstellungen unterscheiden sich in Bezug auf Größe.
Meine Wahl Base64:
quelle
Ihre zweite Lösung ist wahrscheinlich die richtigste. Sie sollten die HTTP-Spezifikation und die Mimetypen so verwenden, wie sie beabsichtigt waren, und die Datei über hochladen
multipart/form-data
. Was den Umgang mit den Beziehungen angeht, würde ich diesen Prozess verwenden (wobei ich bedenke, dass ich nichts über Ihre Annahmen oder Ihr Systemdesign weiß):POST
zu ,/users
um die Benutzereinheit zu erstellen.POST
das Bild/images
, um sicherzustellen , eine Rückkehr -Location
Header , wo das Bild kann per HTTP - Spezifikation abgerufen werden.PATCH
zu/users/carPhoto
und weisen Sie die ID des Fotos in den angegebenenLocation
2 - Header des Schrittes.quelle
Es gibt keine einfache Lösung. Jeder Weg hat seine Vor- und Nachteile. Der kanonische Weg ist jedoch die Verwendung der ersten Option :
multipart/form-data
. Wie der W3-Empfehlungsleitfaden sagtWir senden eigentlich keine Formulare, aber das implizite Prinzip gilt immer noch. Die Verwendung von base64 als binäre Darstellung ist falsch, da Sie das falsche Tool verwenden, um Ihr Ziel zu erreichen. Andererseits zwingt die zweite Option Ihre API-Clients, mehr Arbeit zu leisten, um Ihren API-Service zu nutzen. Sie sollten die harte Arbeit auf der Serverseite erledigen, um eine benutzerfreundliche API bereitzustellen. Die erste Option ist nicht einfach zu debuggen, aber wenn Sie dies tun, ändert sie sich wahrscheinlich nie.
Mit
multipart/form-data
Sie bleiben Sie bei der REST / http-Philosophie. Eine Antwort auf eine ähnliche Frage können Sie hier anzeigen .Eine andere Option, wenn Sie die Alternativen mischen, können Sie mehrteilige / Formulardaten verwenden. Anstatt jeden Wert separat zu senden, können Sie einen Wert mit dem Namen payload mit der darin enthaltenen json-Payload senden. (Ich habe diesen Ansatz mit ASP.NET WebAPI 2 versucht und funktioniert einwandfrei).
quelle