Welche Vor- und Nachteile hat das Entwerfen eines Links als vollständige URL (" http: // Server: Port / Anwendung / Kunden / 1234 ") im Vergleich zum Pfad ("/ application /" beim Entwerfen eines RESTful-Webdienstes mit HATEOAS? Kunden / 1234 ")?
Welche Vor- und Nachteile hat das Entwerfen eines Links als vollständige URL (" http: // Server: Port / Anwendung / Kunden / 1234 ") im Vergleich zum Pfad ("/ application /" beim Entwerfen eines RESTful-Webdienstes mit HATEOAS? Kunden / 1234 ")?
Antworten:
Es gibt eine subtile konzeptionelle Ambiguität, wenn Leute "relative URI" sagen.
Nach der Definition von RFC3986 enthält ein generischer URI:
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
Das Schwierige ist, wenn Schema und Autorität weggelassen werden, kann der "Pfad" -Teil selbst entweder ein absoluter Pfad (beginnt mit /
) oder ein "wurzelloser" relativer Pfad sein. Beispiele:
"http://example.com:8042/over/there?name=ferret"
/over/there
here
oder ./here
oder ../here
oder usw.Wenn also die Frage lautete "ob ein Server in einer erholsamen Antwort einen relativen Pfad erzeugen soll ", lautet die Antwort "Nein" und der detaillierte Grund ist hier verfügbar . Ich denke, die meisten Leute (einschließlich mir) gegen "relative URI" sind tatsächlich gegen "relativen Pfad".
In der Praxis können die meisten serverseitigen MVC-Frameworks leicht einen relativen URI mit einem absoluten Pfad wie z. B. generieren /absolute/path/to/the/controller
, und die Frage lautet: "Die Serverimplementierung sollte scheme://hostname:port
dem absoluten Pfad ein Präfix voranstellen ." Wie die Frage des OP. Da bin ich mir nicht ganz sicher.
Einerseits denke ich immer noch, dass ein Server, der eine vollständige URL zurückgibt, empfohlen wird. Der Server sollte das hostname:port
Ding im Quellcode jedoch niemals so fest codieren (andernfalls würde ich lieber auf relative URL mit absolutem Pfad zurückgreifen). Die Lösung besteht darin, dass das Server-Präfix serverseitig immer aus dem "Host" -Header der HTTP-Anforderung abgerufen wird. Ich bin mir nicht sicher, ob dies in jeder Situation funktioniert.
Andererseits scheint es für den Client nicht sehr mühsam zu sein, den http://example.com:8042
und den absoluten Pfad zu verketten . Immerhin kennt der Client dieses Schema und diesen Domainnamen bereits, wenn er die Anfrage an den Server sendet, oder?
Alles in allem würde ich empfehlen, einen absoluten URI zu verwenden, möglicherweise auf einen relativen URI mit absolutem Pfad zurückzugreifen, niemals einen relativen Pfad zu verwenden .
Es hängt davon ab, wer den Client-Code schreibt. Wenn Sie den Client und den Server schreiben, macht dies keinen großen Unterschied. Sie werden entweder unter dem Schmerz leiden, die URLs auf dem Client oder auf dem Server zu erstellen.
Wenn Sie jedoch den Server erstellen und erwarten, dass andere Benutzer Client-Code schreiben, werden sie Sie viel mehr lieben, wenn Sie vollständige URIs bereitstellen. Das Auflösen relativer URIs kann etwas schwierig sein. Wie Sie sie zuerst auflösen, hängt vom zurückgegebenen Medientyp ab. HTML hat das Basis-Tag, XML kann xml haben: Basis-Tags in jedem verschachtelten Element, Atom-Feeds können eine Basis im Feed und eine andere Basis im Inhalt haben. Wenn Sie Ihrem Client keine expliziten Informationen über den Basis-URI zur Verfügung stellen, muss er den Basis-URI aus dem Anforderungs-URI oder möglicherweise aus dem Content-Location-Header abrufen! Und achten Sie auf diesen nachlaufenden Schrägstrich. Der Basis-URI wird ermittelt, indem alle Zeichen rechts vom letzten Schrägstrich ignoriert werden. Dies bedeutet, dass der nachgestellte Schrägstrich jetzt beim Auflösen relativer URIs von großer Bedeutung ist.
Das einzige andere Problem, das eine kleine Erwähnung erfordert, ist die Dokumentgröße. Wenn Sie eine große Liste von Elementen zurückgeben, bei denen jedes Element mehrere Links haben kann, kann die Verwendung absoluter URLs Ihrer Entität eine erhebliche Anzahl von Bytes hinzufügen, wenn Sie die Entität nicht komprimieren. Dies ist ein Perf-Problem, und Sie müssen von Fall zu Fall entscheiden, ob es von Bedeutung ist.
Wenn Ihre Anwendung skaliert, möchten Sie möglicherweise einen Lastenausgleich, ein Failover usw. durchführen. Wenn Sie absolute URIs zurückgeben, folgen Ihre clientseitigen Apps Ihrer sich entwickelnden Serverkonfiguration.
/xxx/yyy...
) und nicht als vollqualifizierten URI (z http://api.example.com/xxx/yyy...
. B. ).
Verwendung der RayLou-Trichotomie hat sich meine Organisation für die Bevorzugung entschieden (2). Der Hauptgrund besteht darin, XSS-Angriffe (Cross-Site Scripting) zu vermeiden. Das Problem besteht darin, dass nachfolgende Benutzeranforderungen (z. B. eine Authentifizierungsanforderung mit Benutzername und Kennwort) an den eigenen Server des Angreifers * weitergeleitet werden können, wenn ein Angreifer sein eigenes URL-Stammverzeichnis in die vom Server zurückgegebene Antwort einfügen kann.
Einige haben das Problem angesprochen, Anforderungen für den Lastenausgleich an andere Server umleiten zu können, aber (obwohl dies nicht mein Fachgebiet ist) ich würde wetten, dass es bessere Möglichkeiten gibt, den Lastenausgleich zu aktivieren, ohne Clients explizit auf andere umleiten zu müssen Gastgeber.
* Bitte lassen Sie mich wissen, wenn diese Argumentation Mängel aufweist. Das Ziel ist natürlich nicht, alle Angriffe zu verhindern, sondern mindestens einen Angriffsweg.
Sie sollten immer die vollständige URL verwenden. Es fungiert als eindeutige Kennung für die Ressource, da alle URLs eindeutig sein müssen.
Ich würde auch argumentieren, dass Sie konsequent sein sollten. Da der Standort-HTTP-Header eine vollständige URL basierend auf der HTTP-Spezifikation erwartet, wird die vollständige URL im Standort-Header an den Client zurückgesendet, wenn eine neue Ressource erstellt wird. Es wäre seltsam für Sie, eine vollständige URL im Location-Header und dann relative URIs in den Links in Ihrem Antworttext anzugeben.
Location
Headers in der Spezifikation an - einen absoluten URI, der weder das URI-Schema noch den Netzwerkspeicherort des Servers enthält. Während Links und IDs oft zusammengeführt werden, sind sie nicht dasselbe - ersteres hat Kontext, letzteres nicht.
Eine wichtige Überlegung bei großen API-Ergebnissen ist der zusätzliche Netzwerkaufwand für das wiederholte Einbeziehen des vollständigen URI. Ob Sie es glauben oder nicht, gzip löst dieses Problem nicht vollständig (nicht sicher warum). Wir waren schockiert darüber, wie viel Speicherplatz die vollständige URI einnahm, als ein Ergebnis Hunderte von Links enthielt.
Ein Nachteil der Verwendung absoluter URIs besteht darin, dass die API nicht als Proxy verwendet werden kann.
Nimm es zurück ... nicht wahr. Sie sollten eine vollständige URL einschließlich der Domain angeben.
In Bezug auf die Profis sehe ich die Reduzierung der zu übertragenden Bytes auf Kosten einer zusätzlichen Behandlung, die ein Client für den (absoluten) Pfad benötigt. Wenn Sie unbedingt jedes Byte speichern möchten, selbst nachdem Sie die Inhaltscodierung als gzip, die ordnungsgemäße Verwendung von Caching-Headern, die Verwendung von Etags und bedingte Anforderungen auf dem Client versucht haben, kann dies am Ende erforderlich sein, aber ich erwarte viel höhere Renditen Ihre Bemühungen waren anderswo.
In Bezug auf die Nachteile sehe ich einen Kontrollverlust darüber, wie Sie den Clientfluss zwischen Ressourcen in Zukunft steuern können (Lastausgleich, A / B-Tests, ...), und ich würde dies als schlechte Praxis bei der Verwaltung eines Webs betrachten API. Die von Ihnen angegebene URL ist für den Client nicht mehr grundsätzlich undurchsichtig (siehe Tim Berners-Lee Axiome der Webarchitektur zur URI-Opazität ). Am Ende sind Sie dafür verantwortlich, die Kunden über die kreative Nutzung Ihrer API zufrieden zu stellen, auch wenn es nur um die Struktur Ihres URL-Bereichs geht. Sollten Sie jemals eine explizit definierte URL-Änderung zulassen müssen, sollten Sie die Verwendung von URI-Vorlagen in Betracht ziehen, wie sie in der Hypertext-Anwendungssprache verwendet werden .