Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi ContentType in TRESTClient (https://www.delphipraxis.net/199960-contenttype-trestclient.html)

Scurra 6. Mär 2019 06:33

Delphi-Version: 10 Seattle

ContentType in TRESTClient
 
Hallo zusammen,

wir sind in unserer Firma gerade dabei, von Seattle auf 10.3.1 Rio umzusteigen, was einige Probleme verursacht hat. Die meisten davon konnte man leicht lösen, beim TRESTClient bin ich aber auf eine sehr merkwürdige Implementierung gestoßen, die - soweit ich das bislang einschätzen kann - den TRESTClient unbrauchbar macht.

Meine Hoffnung ist, dass das Problem darin besteht, dass ich den Rest-Client bisher falsch benutzt habe. Deshalb richte ich die Frage mal hier ins Forum und hoffe, dass mir jemand helfen kann:

Wie setzt man den content-type für einen Request richtig?

Ich benutze den TRESTClient beispielsweise für eine Kommunikation mit Klarna und Klarna erwartet als content-type so etwas wie "application/vnd.klarna.checkout.aggregated-order-v2+json". Das Problem ist, dass der TRESTClient den content-type in der Execute-Methode jedes Mal durch einen der X verschiedenen "Standard"-content-types ersetzt, in meinem Fall beispielsweise durch "application/json". Das führt dazu, dass Klarna sich mit der Meldung "415 Unsupported Media Type" zurückmeldet und ich keine erfolgreiche Anfrage mehr durch bekomme.

Bei der "alten" Delphi-Version wurde, nachdem der content-type in der Execute-Methode überschrieben wurde, die virtuelle Methode "DoPrepareRequestBody" aufgerufen, die wir dazu misbraucht haben, den content-type wieder auf den gewünschten Wert zu setzen. Bei Rio hat sich hier aber die Reihenfolge vertauscht, so dass dies jetzt nicht mehr möglich ist.

TiGü 6. Mär 2019 09:18

AW: ContentType in TRESTClient
 
Nur eine Idee:
Wäre es für euch eine Möglichkeit, die Unit REST.Types zu kopieren, mit in euer Projekt aufzunehmen und zu patchen?
So dass ihr euren Typ in TRESTContentType und entsprechend
Delphi-Quellcode:
function ContentTypeToString(AContentType: TRESTContentType): string;
anpasst?
Man müsste aber prüfen, in wie weit das mit den anderen REST-Units dann noch kompatibel ist. Ggf. muss man sich mehrere davon ins Projekt nehmen.
Dann kann man aber auch gleich die Execute-Methode anpassen.

Weitere Möglichkeit:
Unter Windows würde die Möglichkeit bestehen, sich in die Winapi-Funktion WinHttpAddRequestHeaders reinzuhängen (intercept) und den Wert beim Aufruf dort auszutauschen.
Diese wird in procedure
Delphi-Quellcode:
TWinHTTPRequest.AddHeader(const AName, AValue: string);
aus System.Net.HttpClient.Win aufgerufen.
Natürlich insofern, dass dies in Rio verwendet wird. Ich kann im Moment nur in Tokyo nachschauen.

TiGü 6. Mär 2019 09:20

AW: ContentType in TRESTClient
 
Hier die Idee mit den intercept/hooken:
https://www.delphipraxis.net/198305-...-tls-win7.html

Schokohase 6. Mär 2019 09:31

AW: ContentType in TRESTClient
 
Ich würde so vorgehen
https://www.delphipraxis.net/1416350-post2.html

Scurra 6. Mär 2019 09:41

AW: ContentType in TRESTClient
 
Zitat:

Zitat von TiGü (Beitrag 1427037)
Wäre es für euch eine Möglichkeit, die Unit REST.Types zu kopieren, mit in euer Projekt aufzunehmen und zu patchen?
So dass ihr euren Typ in TRESTContentType und entsprechend
Delphi-Quellcode:
function ContentTypeToString(AContentType: TRESTContentType): string;
anpasst?
Man müsste aber prüfen, in wie weit das mit den anderen REST-Units dann noch kompatibel ist. Ggf. muss man sich mehrere davon ins Projekt nehmen.
Dann kann man aber auch gleich die Execute-Methode anpassen.

Das war auch unsere Idee.
Ich bin mir nur nicht sicher, ob das mit dem content-type ein Bug ist oder ein Feature ;) Letzteres würde bedeuten, dass man beim zukünftigen Wechsel auf neuere Delphi-Versionen immer wieder die Implementierung anpassen muss.


Zitat:

Weitere Möglichkeit:
Unter Windows würde die Möglichkeit bestehen, sich in die Winapi-Funktion WinHttpAddRequestHeaders reinzuhängen (intercept) und den Wert beim Aufruf dort auszutauschen.
Diese wird in procedure
Delphi-Quellcode:
TWinHTTPRequest.AddHeader(const AName, AValue: string);
aus System.Net.HttpClient.Win aufgerufen.
Natürlich insofern, dass dies in Rio verwendet wird. Ich kann im Moment nur in Tokyo nachschauen.
Dieses Intercepten würde aber auf Anwendungsebene ablaufen, oder? Also wenn ich den REST-Client an zwei verschiedenen Stellen verwende, weiß ich beim Intercepten nicht, von welcher Stelle aus die Funktion aufgerufen wurde. In diesem Fall wäre es nämlich schwer bis unmöglich, herauszufinden, auf welchen content-type man den Header setzen muss.

Aber danke jedenfalls schon mal für die Idee und den Link!

TiGü 6. Mär 2019 10:59

AW: ContentType in TRESTClient
 
Zitat:

Zitat von Scurra (Beitrag 1427040)
Dieses Intercepten würde aber auf Anwendungsebene ablaufen, oder? Also wenn ich den REST-Client an zwei verschiedenen Stellen verwende, weiß ich beim Intercepten nicht, von welcher Stelle aus die Funktion aufgerufen wurde. In diesem Fall wäre es nämlich schwer bis unmöglich, herauszufinden, auf welchen content-type man den Header setzen muss.

Aber danke jedenfalls schon mal für die Idee und den Link!

Ja, das gilt dann nur für eure Anwendung.

Klar, es ist etwas tricky, falls die Contenttypes variieren, aber man kann sich da ggf. mit etwas Globalen behelfen(oh mein Gott, hat er das wirklich geschrieben?).

Also an einer Stelle (eigene Unit) den aktuellen, jetzt gleich zu verwendeten Contenttype setzen (also bevor ihr Request.Execute aufruft) und im Intercepter auslesen und ersetzen.

Klar ist das alles nur Gebastel, aber euren Code jetzt komplett auf eine saubere Lösung wie von Schokohase vorgeschlagen umzustricken, könnt ihr machen wenn ganz viel Zeit ist.

Mit der Intercept-Lösung könnt ihr ja per {IFDEF Compilerversion=XYZ} arbeiten.
So dass ihr in der ggf. nächsten Version den Fix nicht verwenden müsst, wenn da alles wieder schön sein sollte.

Bbommel 6. Mär 2019 13:06

AW: ContentType in TRESTClient
 
Eine einfache Lösung habe ich leider auch nicht, aber ich hatte vor einiger Zeit das selbe Problem und hatte dafür mal ein Ticket aufgemacht mit einem einfachen Lösungsvorschlag.

https://quality.embarcadero.com/browse/RSP-19793

Vielleicht könnt ihr ja mal dafür voten oder kommentieren, in der Hoffnung, dass es dann auch mal umgesetzt wird.

Union 6. Mär 2019 13:14

AW: ContentType in TRESTClient
 
So geht es also definitiv nicht?

Delphi-Quellcode:
 RestClient.ContentType := 'application/veryspecialjson+V42';
 RestRequest.Params.AddItem('Content-Type',
    RestClient.ContentType,
    TRESTRequestParameterKind.pkHTTPHEADER,
    [TRESTRequestParameterOption.poDoNotEncode],
    TRESTContentType.ctNone);

Bbommel 6. Mär 2019 13:22

AW: ContentType in TRESTClient
 
Wenn ich mich an meine Odysee von vor einem Jahr richtig erinnere, hast du dann den Content-Type entweder doppelt drin stehen - also einmal den selbst gesetzten und den automatischen - oder es wird das eigene Feld doch wieder überschrieben. Ich meine, es war ersteres, also dass er doppelt vorkommt.

Scurra 6. Mär 2019 15:25

AW: ContentType in TRESTClient
 
Zitat:

Zitat von Union (Beitrag 1427070)
So geht es also definitiv nicht?

Delphi-Quellcode:
 RestClient.ContentType := 'application/veryspecialjson+V42';
 RestRequest.Params.AddItem('Content-Type',
    RestClient.ContentType,
    TRESTRequestParameterKind.pkHTTPHEADER,
    [TRESTRequestParameterOption.poDoNotEncode],
    TRESTContentType.ctNone);

Zitat:

Wenn ich mich an meine Odysee von vor einem Jahr richtig erinnere, hast du dann den Content-Type entweder doppelt drin stehen - also einmal den selbst gesetzten und den automatischen - oder es wird das eigene Feld doch wieder überschrieben. Ich meine, es war ersteres, also dass er doppelt vorkommt.
Diesen Vorschlag habe ich neulich schon einmal im Internet gefunden und es kam weiterhin "Unsupported media type" zurück. Ich wollte jetzt gerade bBommels Aussage mit Charles überprüfen, also ob der Header doppelt auftaucht oder ob er wieder überschrieben wird, aber nun hat es plötzlich funktioniert.

Irgendwas habe ich gestern wohl falsch gemacht.

Ich halte es zwar für ein falsches Design, dass die Property "ContentType" von außen gesetzt werden kann, obwohl das überhaupt keine Auswirkung auf den Request hat, aber nun ja, für mich zählt erst einmal, dass ich eine (einfache) Lösung habe.

Danke jedenfalls für eure Hilfe :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:56 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz