Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Die Delphi-IDE (https://www.delphipraxis.net/62-die-delphi-ide/)
-   -   REST via Indy IdHTTP, Problem mit JSON/Content-Length (https://www.delphipraxis.net/213549-rest-via-indy-idhttp-problem-mit-json-content-length.html)

thomaskroger 16. Aug 2023 11:01

REST via Indy IdHTTP, Problem mit JSON/Content-Length
 
Moin,

bei einer (XE6-)REST-Kommunikation via Indy IdHTTP als POST tritt ein Problem mit der Content-Length und dem JSON-Format auf.

Wenn ein JSON gesendet wird:
Body:
Code:
{
 "recordtype" : "REC1",
 "dealer": "xxxx",
 "branch":xx,
 "ordernumber": xxxxxx
}
komme eine Socket-Error#10054 und keine Response-JSON vom Server zurück.

Das funktioniert übrigens in POSTMAN problemlos:
Code:
POST https://xxxxxxmobile-xx.xxxxx.com/xxx/api/v2/xxx/xxxx/xxxxxxxxxxxx
POST /xxx/api/v2/xxx/xxxx/xxxxxxxxxxxxx HTTP/1.1
Content-Type: application/json
Authorization: Bearer ey...Tw
Host: xxxxxxmobile-xx.xxxxx.com
Content-Length: 88
Cookie: 053...20a; TS0172207b=01...94b
{
"recordtype" : "REC1",
"dealer": "xxxx",
"branch":xx,
"ordernumber": xxxxxx
}


HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
date: Tue, 15 Aug 2023 11:18:56 GMT
vary: Accept-Encoding
x-kong-upstream-latency: 90
x-kong-proxy-latency: 18
via: kong/2.0.4
Set-Cookie: TS0172207b=01...c72bf; Path=/; Domain=.xxxxxxmobile-xx.xxxxx.com; Secure; HTTPOnly
Transfer-Encoding: chunked

{
"recordtype": "REC1",
"dealer": "xxxx ",
"branch": xx,
"ordernumber": xxxxxx,
"returncode": "00"
}

Dann ein JSON im Format:
Code:
{"recordtype":"REC1","dealer":"xxxx","branch":xx,"ordernumber":xxxxxx}
mit der "Content-Length: 0" (! s.u.)

Jetzt reagiert der Server mit der Antwort:
Code:
HTTP/1.1 400 Bad Request
{
    "errorCode": "URL0001",
    "message": "No input dataÜ"
}
Code:
Req:
POST /xxx/api/v2/xxx/xxxx/xxxxxxxxxxxx HTTP/1.1
Content-Type: application/json
Content-Length: 0
Authorization: Bearer ey...5AQ
Cookie: 053...20a; TS0172207b=01...1c
Body: {"recordtype":"REC1","dealer":"xxxx","branch":xx,"ordernumber":xxxxxx}
Host: xxxxxxmobile-xx.xxxxx.com
Accept: */*
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)

Resp: HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
date: Tue, 15 Aug 2023 17:57:22 GMT
x-kong-upstream-latency: 50
x-kong-proxy-latency: 17
via: kong/2.0.4
Set-Cookie: TS0......c75; Path=/; Domain=.xxxxxxmobile-xx.xxxxx.com; Secure; HTTPOnly
Transfer-Encoding: chunked

Resp:
{
    "errorCode": "URL0001",
    "message": "No input dataÜ"
}

Da Content-Length: 0 ist, wie von IdHTTP/POST generiert, diesmal MIT Content-Length: 0 UND Content-Length: 72:

Code:
Req:
POST /xxx/api/v2/xxx/xxxx/xxxxxxxxxxxxx HTTP/1.1
Content-Type: application/json
Content-Length: 0
Authorization: Bearer ey..qg
Cookie: 053...0a; TS0172207b=01f...1c
Body: {"recordtype":"REC1","dealer":"xxxx","branch":xx,"ordernumber":xxxxxx}
Content-Length: 72
Host: xxxxxxmobile-xx.xxxxx.com
Accept: */*
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)
das POST und das Programm hängt ohne response.




Delphi-Quellcode:
      IdLogFile.Filename:='LogOrder.txt';
      IdLogFile.Active:=true;

      IdHTTP.Response.Clear;
      IdHTTP.Request.Clear;

      with IdSSLIOHandlerSocketOpenSSL do
      begin
        SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
        SSLOptions.Mode := sslmClient;
        SSLOptions.VerifyMode := [];
        SSLOptions.VerifyDepth := 0;
        DefStringEncoding := enUTF8;
        ReadTimeout    := 1000;
        ConnectTimeout := 1000;
      end;

      with IdHTTP do
      begin
        ConnectTimeout := 1000;
        AllowCookies   := True;
        HandleRedirects := True;
        IOHandler      := IdSSLIOHandlerSocketOpenSSL;
      end;

      with IdHTTP.Request do
      begin
        Clear;
        BasicAuthentication := false;
        Accept:='*/*';
        ContentType:='application/json';
        CustomHeaders.AddValue('Authorization', 'Bearer ' + token);
        CustomHeaders.AddValue('Cookie','053...20a; TS0172207b=01f...1c');
        CustomHeaders.AddValue('Body',Body);
//      ContentLength:=length(Body);  //see Remy Lebeau !
//      CustomHeaders.AddValue('Content-Length',length(Body).ToString());
      end;

      rs :=IdHTTP.Post(BaseURL, ResponseList);
    except
      on E: Exception do
      begin
Der Server hat offenbar ein Problem mit dem JSON-Format des IdHTTP-Body. Gut, das darf er, er nimmt ja das formatlose JSON.
Mal rhetorisch gefragt: was macht IdHTTP mit dem JSON dass der Server es nicht annimmt? Im Log sieht es harmlos aus.

IdHTTP/POST generiert eine Content-Length: 0 und das mag der Server auch nicht.
Wie Remy Lebeau so richtig sagt: DO NOT set a ContentLength manually, let Post() fill it in for you..
Ok, wie überrede ich IdHTTP/POST dazu, eine richtige Content-Length über length(Body) zu bilden?

mny tnx!
Thomas

jaenicke 16. Aug 2023 11:19

AW: REST via Indy IdHTTP, Problem mit JSON/Content-Length
 
So etwas debugge ich meistens sehr einfach:
Ich lege mir ein Skript auf einen Server, das loggt, was dorthin gesendet wird.

Auf diese Weise kann ich auch einfach an eine URL ohne SSL die Anfragen schicken und so beide z.B. in Wireshark vergleichen, da diese dort im Klartext erscheinen.

Das kann man natürlich auch mit einem Proxy oder ähnlichem erreichen, aber so ist es ganz einfach.

thomaskroger 16. Aug 2023 11:29

gelöst: REST via Indy IdHTTP, Problem mit JSON/Content-Length
 
@Sebastian
Guter Tip!


Die Lösung für Content-Length ist einfach: (JSON im Body:string)
Delphi-Quellcode:
  RequestBody:=TStringStream.Create(Body,TEncoding.UTF8);
...
  Response:=IdHTTP.Post(Base, RequestBody);
Und schon stimmt die Content-Length. Also nicht: CustomHeaders.AddValue('Body',Body);

... wer lesen kann ist klar im Vorteil...
mny tnx
Thomas

himitsu 16. Aug 2023 12:58

AW: gelöst: REST via Indy IdHTTP, Problem mit JSON/Content-Length
 
Jupp, die Daten "nach" den Headern, mit einer Leerzeile dawischen (welche das Ende der Header kennzeichnet)

Drum kann das so
Code:
Cookie: 053...20a; TS0172207b=01...94b
{
eigentlich auch nicht richtig sein.

mjustin 16. Aug 2023 13:17

AW: REST via Indy IdHTTP, Problem mit JSON/Content-Length
 
Zitat:

Zitat von thomaskroger (Beitrag 1525656)
bei einer (XE6-)REST-Kommunikation via Indy IdHTTP als POST tritt ein Problem mit der Content-Length und dem JSON-Format auf.

Ist es die Indy Version in XE6 oder eine aktuelle?
Wenn es ein Bug in der alten Indy Version ist, stehen die Chancen gut dass dieser mittlerweile behoben ist.

Die neue Version kann testweise einfach in einem neuen Verzeichnis entpackt werden - eine Package-Installation ist nicht unbedingt notwendig.

thomaskroger 16. Aug 2023 13:56

AW: REST via Indy IdHTTP, Problem mit JSON/Content-Length
 
@himitsu
Zitat:

die Daten "nach" den Headern, mit einer Leerzeile dazwischen
jap, richtig. Ich habe den Text zur Darstellung komprimiert.

@mjustin
Zitat:

Die neue Version kann testweise einfach in einem neuen Verzeichnis entpackt werden
Gibt es einen Link für eine Anleitung zur harmlosen Test-Installation? Ich hab mit letztens einen Wolf geritten um eine gescheiterte Indy-Installation wieder herzustellen:
https://www.delphipraxis.net/213521-...rt-werden.html

himitsu 16. Aug 2023 16:12

AW: REST via Indy IdHTTP, Problem mit JSON/Content-Length
 
Einfach z.B. von GitHub runterladen,
dann das SourceVerzeichnis im Suchpfad (Projektoptionen) des aktuellen Programms.
Oder die Indy-Quellcodes ins Projektverzeichnis kopieren.

Es werden dann direkt die PAS einkompiliert (Laufzeitpackages=False),
drum sind keine DCU oder DCP/BPL nötig, weswegen es auch nicht nörtig ist das Indy-Setup auszuführen.

Du kannst dabei bloß keine Form im FormDesigner öffnen, wo komponenten drauf liegen.
(bzw. es geht womöglich, wobei im Designer dann aber die derzeit installierte Version genutzt würde)


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:31 Uhr.

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