AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke MultipartFormData und TRESTRequest
Thema durchsuchen
Ansicht
Themen-Optionen

MultipartFormData und TRESTRequest

Ein Thema von Rabenrecht · begonnen am 20. Okt 2022 · letzter Beitrag vom 27. Okt 2022
Antwort Antwort
Rabenrecht

Registriert seit: 9. Dez 2016
79 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

MultipartFormData und TRESTRequest

  Alt 20. Okt 2022, 10:45
So, bin nach langer Zeit (3 Jahre+) mal wieder an einer ernsthaften Entwicklung in Delphi dran: eine Schnittstelle (extern), die bislang über Soap angesprochen wurde, hat den Support für Soap nun endgültig aufgekündigt. Ab jetzt ist die Rest-Api zu verwenden.

Es muss also ein Rest-Api-Client her. Soweit so gut.

Die Rest-Api erwartet an einer Stelle ein multipart-formdata body. Die einzelnen Parts können wiederum die verschiedensten Content Types sein. Ein application/json ist immer dabei und dann diverse Dateien, also application/pdf, image/png, text/plain, whatever.


Und genau da stehe ich auf dem Schlauch, wie ich das in Delphi hinbekomme.

Ich nutze die unter REST.Client bereit gestellten Klassen, dh. TRESTClient, TRESTRequest und TRESTResponse.

Hier komme ich für einen Multipart-Body aber nicht wirklich weiter.
Zwar lässt sich mit FRestRequest.AddParameter('myName', 'myValue', TRESTRequestParameterKind.pkREQUESTBODY) ein Multipart-Body erzeugen, der jeweilige content type lässt sich so aber nicht festlegen. Der content type ist aber ziemlich wichtig

Nach etwas Recherche bin ich auf System.Net.Mime.TMultipartFormData gestoßen. Die Klasse bietet ziemlich sinnvoll aussehende Methoden. Zb. TMultipartFormData.AddFile, wo ich einfach nur den Datei-Pfad angeben brauche und sich damit vielleicht auch meine nächste Frage, wie ich denn in Delphi aus einer Datei den passenden Octet-Stream erzeuge, erübrigt

Nur sehe ich gar nicht, wie TMultipartFormData mit den REST.Client Klassen zusammenspielt.


Da dachte ich mir, vielleicht haben ja die Delphi-Experten den ein oder anderen Tipp für mich

Derzeit ist Delphi 10.2 im Einsatz.
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
3.910 Beiträge
 
Delphi 12 Athens
 
#2

AW: MultipartFormData und TRESTRequest

  Alt 20. Okt 2022, 11:41
Wenig Zeit ... hilft Dir das weiter ?
https://en.delphipraxis.net/topic/74...#comment-62684
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.021 Beiträge
 
Delphi 12 Athens
 
#3

AW: MultipartFormData und TRESTRequest

  Alt 20. Okt 2022, 11:44
Wenn du mindestens ein File per AddFile zum Request hinzugefügt hast, wird der ContentType automatisch auf ctMULTIPART_FORM_DATA gesetzt.

Um mehrere AddBody-Calls abzusetzen, ohne dabei den vorigen Body zu überschreiben, funktioniert das nur mit diesem Overload:
procedure AddBody(ABodyContent: string; AContentType: TRESTContentType = ctNone); overload;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Rabenrecht

Registriert seit: 9. Dez 2016
79 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#4

AW: MultipartFormData und TRESTRequest

  Alt 25. Okt 2022, 13:41
Danke, das hat mich auf den richtigen Weg gebracht!

Bin noch über diverse weitere Schwierigkeiten gestolpert, aber dafür mache ich vielleicht besser eigene Threads auf
  Mit Zitat antworten Zitat
Rabenrecht

Registriert seit: 9. Dez 2016
79 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: MultipartFormData und TRESTRequest

  Alt 26. Okt 2022, 16:39
Ok, bin doch noch nicht durch mit dem Thema

Ich bekomme es einfach nicht hin, die nicht-file Teile des Bodies sowohl mit einem von mir gewählten Namen UND dem von mir gewählten Content Type hinzuzufügen.

Und dabei nutze ich schon TRESTRequestParameterList.AddItem, bei dem ich beides tatsächlich angeben kann.

Der angegebene Name wird berücksichtigt, der Content Type aber warum auch immer trotzdem auf text/plain gesetzt (anstatt des angegebenen application/json).

Langsam gehen mir die Ideen aus
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.021 Beiträge
 
Delphi 12 Athens
 
#6

AW: MultipartFormData und TRESTRequest

  Alt 26. Okt 2022, 16:52
In dem Fall solltest du mal ein Beispiel geben, wie der Request genau aussehen soll, was du aktuell raus bekommst und wie du das gemacht hast.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Rabenrecht

Registriert seit: 9. Dez 2016
79 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#7

AW: MultipartFormData und TRESTRequest

  Alt 27. Okt 2022, 07:30
Ok

Soll:
Code:
POST /api/derEndpunkt?QueryParameter=1234 HTTP/1.1
Connection: Keep-Alive
Content-Type: multipart/form-data; boundary=--------102722082331395
Accept: application/json, application/*+json
Accept-Charset: UTF-8, *;q=0.8
Authorization: Basic cm9vdDpvcHRpbWFs
Cookie: JSESSIONID=CACA72D331F84414ADF4E7C8CFFE02C2
User-Agent: Embarcadero RESTClient/1.0
Content-Length: 9121
Host: zielhost

----------102722082331395
Content-Disposition: form-data; name="nameJson"
Content-Type: application/json
Content-Transfer-Encoding: quoted-printable

{"key":"value"}
----------102722082331395
Content-Disposition: form-data; name="nameFile"; filename="Test_Bild.png"
Content-Type: image/png
Content-Transfer-Encoding: binary

[das serialisierte Bild]
----------102722082331395--

Was ich mache:
Delphi-Quellcode:
procedure PostObject;
begin
  FRestRequest.Params.Clear;
  FRestRequest.ClearBody;
  FRestRequest.Response.ResetToDefaults;
  FRestRequest.Method := rmPOST;
  FRestRequest.Resource := '/api/derEndpunkt?QueryParameter=1234';

  //Variante 1
  //FRestRequest.AddParameter('nameJson', '{"key":"value"}', false);

  //Variante 2
  //FRestRequest.AddParameter('nameJson', '{"key":"value"}', TRESTRequestParameterKind.pkREQUESTBODY);
  //FRestRequest.Params.ParameterByName('nameJson').ContentType := TRESTContentType.ctAPPLICATION_JSON;

  //Variante 3
  FRestRequest.Params.AddItem('nameJson', '{"key":"value"}', TRESTRequestParameterKind.pkREQUESTBODY, [], TRESTContentType.ctAPPLICATION_JSON);

  //Variante 4
  //FRestRequest.Body.Add('{"key":"value"}',TRESTContentType.ctAPPLICATION_JSON);

  FRestRequest.AddFile('nameFile', 'PfadZurPng', TRESTContentType.ctIMAGE_PNG);

  FRestRequest.Accept := 'application/json, application/*+json';
  FRestRequest.Execute;
end;
Varianten 1, 2 und 3 führen allen zum gleichen Ergebnis:
Code:
POST /api/derEndpunkt?QueryParameter=1234 HTTP/1.1
Connection: Keep-Alive
Content-Type: multipart/form-data; boundary=--------102722082331395
Accept: application/json, application/*+json
Accept-Charset: UTF-8, *;q=0.8
Authorization: Basic cm9vdDpvcHRpbWFs
Cookie: JSESSIONID=CACA72D331F84414ADF4E7C8CFFE02C2
User-Agent: Embarcadero RESTClient/1.0
Content-Length: 9121
Host: zielhost

----------102722082331395
Content-Disposition: form-data; name="nameJson"
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable

{"key":"value"}
----------102722082331395
Content-Disposition: form-data; name="nameFile"; filename="Test_Bild.png"
Content-Type: image/png
Content-Transfer-Encoding: binary

[das serialisierte Bild]
----------102722082331395--
Der Content-Type des Json Parts des Request ist immer text/plain.

Mit Variante 4 wird der Content Type zwar richtig auf application/json gesetzt, der Name ist aber generiert. Klar, habe ja auch keinen explizit angegeben.

Geändert von Rabenrecht (27. Okt 2022 um 07:32 Uhr)
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: MultipartFormData und TRESTRequest

  Alt 27. Okt 2022, 09:45
Debug doch mal mit Debug-DCUs aktiviert rein?
Du müsstest bei beiden Varianten 3 und 4 in einer Überladung von TRESTRequestParameterList.AddItem enden.
Hier kannst du doch feststellen, wer oder was dir den ContentType überschreibt.

Wenn es da noch okay ist, sollte TCustomRESTRequest.Execute das nächste Debug-Ziel sein.
Da gibt es im oberen Drittel irgendwann den Aufruf von TCustomRESTRequest.ContentType().
Hier würde ich debuggen.
Ältere Delphi-Versionen haben da vielleicht noch nicht alle Spezialitäten drin bzw. unterstützen so Multipart-Sachen noch nicht so gut.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.021 Beiträge
 
Delphi 12 Athens
 
#9

AW: MultipartFormData und TRESTRequest

  Alt 27. Okt 2022, 13:44
Das scheint ein Problem mit Delphi 10.2 zu sein. Der verantwortliche Code liegt in in TCustomRESTRequest.DoPrepareRequestBody Zeile 2742
Delphi-Quellcode:
      if LContentType = TRESTContentType.ctMULTIPART_FORM_DATA then
      begin
        // Multipart
        // For multipart names of body parameters are written - in contrast to WWWForm (see below)
        if (LParam.Kind = TRESTRequestParameterKind.pkFile) then
          LMultipartPeerStream.AddFormFile(LParam.Name, LParam.Value, ContentTypeToString(LParam.ContentType))
        else
          LMultipartPeerStream.AddFormField(LParam.Name, LParam.Value);
      end
In Delphi 11 sieht die Sequenz dann so aus
Delphi-Quellcode:
        if SameText(AContentType, TRESTContentType.ctMULTIPART_FORM_DATA) then
        begin
          // Multipart
          // For multipart names of body parameters are written - in contrast to WWWForm (see below)
          if LParam.Stream <> nil then
            LMultipartFormData.AddStream(LParam.Name, LParam.Stream, LParam.Value,
              ContentTypeToString(LParam.ContentType))
          else if LParam.Kind = TRESTRequestParameterKind.pkFile then
            LMultipartFormData.AddFile(LParam.Name, LParam.Value,
              ContentTypeToString(LParam.ContentType))
          else
            LMultipartFormData.AddField(LParam.Name, LParam.Value,
              ContentTypeToString(LParam.ContentType));
        end
Im Gegensatz zu 10.2 wird hier der ContentType des Parameters mit übergeben.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Rabenrecht

Registriert seit: 9. Dez 2016
79 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#10

AW: MultipartFormData und TRESTRequest

  Alt 27. Okt 2022, 15:10
Ja, habe das jetzt auch so im Code nachvollzogen.

Danke fürs Nachschauen, Uwe!

So, als Workarround hätte ich nun die Option, den Json-Teil des Bodys als Datei zu speichern und dann mit AddFile hinzufügen...

Ich habe geschaut, ob ich das irgendwie austricksen kann, aber sobald LParam.Kind = TRESTRequestParameterKind.pkFile ist, wird der Wert des Parameters als Dateipfad interpretiert.
Mein "Json als Datei abspeichern" Umweg scheint die einzige Möglichkeit zu sein, die mir in Tokyo bleibt

Mal sehen, ob das klappt.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:36 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