![]() |
TWebModule und Multipart
Hi,
ich habe einen AppServer als Standalone laufen, in dem ich über TWebModule die entsprechenden Requests auswerte und bearbeite. Die Anfrage werden über eine Webseite, die auf einem anderen Host liegt erzeugt. Jetzt bin ich auf ein Problem gestoßen. Wenn ich in einem Request ein Picture mitgesendet wird, wird der Request als Multipart geschickt. Wenn als Method im WebFormular Get verwendet wird, erhalte ich zwar alle Fields, jedoch ist Files.Count immer 0. Das ist ja Okay. Ändere ich die Method auf Post, ist wird beim Auswerten des Content ein EEncodingError ausgeworfen. Die Daten sind aber im RawContent vorhanden, allerdings natürlich gänzlich anders als bei der Übertragung als GET. Wie kriege ich es hin, dass der Request richtig geparst wird? |
AW: TWebModule und Multipart
Füge in der Uses Liste deines TWebModul's die Unit "Web.ReqMulti" hinzu. Danach sollte Files abgefüllt sein.
|
AW: TWebModule und Multipart
Danke. Habe ich bereits drin (hatte das irgendwo gelesen).
Leider ist das Verhalten mit und ohne gleich. Mittlerweise habe ich herausgefunden, dass es nicht zwingend am POST liegt, sondern an dem Parameter
Code:
im Form-Tag.
enctype="multipart/form-data"
Ohne das enctype wird natürlich auch wieder keine Datei angahängt. |
AW: TWebModule und Multipart
Wie wird denn das Senden der Datei auf Client-Seite (also der Client aus Sicht deines Delphi-Servers) erzeugt? Hängt da auch irgendein Code hinter, der die Datei sendet? Möglicherweise liegt da das Problem?
|
AW: TWebModule und Multipart
Zum Test erst einmal einfach so:
Code:
<html>
<head> <meta charset="utf8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <form id="myForm" action="http://localhost:8443/senddata.php" method="post" enctype="multipart/form-data"> <input type="hidden" name="DataType" value="fileupload"> <input type="file" size="120" name="myfile"> <input type="text" size="20" name="mimetype" value="image/bmp"> <input type="submit" value="upload"> </form> </body> </html> |
AW: TWebModule und Multipart
Lasse ich "enctype" weg, springt er mir auch in der Unit Web.ReqMulti in die Procedure "IsMultipartForm", liefert jedoch ein False zurück, weil es ja nicht drin steht.
Wenn enctype="multipart/form-data" jedoch drin ist, testet er gar nicht erst auf IsMultipartForm. |
AW: TWebModule und Multipart
Sieht jetzt erstmal unspektakulär aus. Macht denn das senddata.php irgendwas spannendes, was zu Problemen führen könnte?
|
AW: TWebModule und Multipart
Die Action der Form geht doch da aber auf eine php Seite, also wie soll das dann dein Webmodul erreichen oder fehlt hier noch eine wichtige Info, die du uns hier vorenthälst? Un djam enctype="multipart/form-data" musst du auf jeden Fall verwenden, sonst bekommst du keine Dateidaten.
Das mit dem MultiReq nutzte ich schon länger und das geht ohne Probleme bei mir, nur ist es bei mir eben eine Delphi Webapplikation die das empfängt. Bei dir eine PHP Seite?! Wo kommt da das Webmodul zum Einsatz? |
AW: TWebModule und Multipart
"senddata.php" ist einfach nur mein TWebActionItem.PathInfo um unterschiedliche Abfragen ein bischen zu unterscheiden. Hätte auch alles über die DefaultAction laufen können.
Gemacht wird da noch nichts, außer dass ich die Fields auswerte um dann die Daten zu Verarbeiten, bzw. das Response zu erzeugen. Solange kein Multipart drin ist, hat das auch alles wunderbar geklappt. Jetzt will ich aber auch Bilder empfangen. Zum testen habe ich mir das ganz simple Html-Formular genommen. Wie klinkt sich denn das ReqMulti ein? Und warum wird das bei enctype="multipart/form-data" ignoriert? Ist denn enctype="multipart/form-data" richtig für Formulare mit File-Upload? |
AW: TWebModule und Multipart
Das mit php kannst du natürlich so machen, nur ist das sehr verwirrend, weil das wie ein PHP Server ausieht, es aber garnicht ist. Natürlich ist es korrekt nicht alles über das default Action zu machen, nur würde ich da halt die PathInfo auf "/upload" oder soaws setzen und nicht etwas vorgaukeln was nicht ist. Die Action wärer dann z.B. so:
![]() Ich nutze das aber etwas anderst als du, da ich für den Upload ein JS Plugin ( ![]() Ob das also überhaupt so funktioniert mit einer Form und einem Input type "file", müsste ich selber mal testen. Für meinen Fall war es aber so, dass gewünscht wurde, dass der Kunde mehrere Dateien hochladen kann und das wäre mit einer simplen Form nicht mehr machbar gewesen. In deinem Fall mit einer einzlnen Form müsste aber auf jeden Fall enctype="multipart/form-data" bei der Form gesetzt sein. |
AW: TWebModule und Multipart
Ich habe mal geschaut, wie es aussieht, wenn ein Client meinem Server eine Datei sendet, also mal den RawContent aus dem Request ins Log geschrieben:
Code:
-----------------------------167835985122627247241915400059
Content-Disposition: form-data; name="files[]"; filename="changeTimeValue.dcu" Content-Type: application/octet-stream [...] Hier ist also auch "form-data" vorhanden, das sollte soweit kein Problem sein. Liegt es vielleicht schlicht daran, dass dein <input>-Element für die Dateien nicht "files[]" heißt? Ähnlich wie bei Rolf läuft das eigentliche Senden der Dateien bei mir allerdings auch per Javascript im Browser, wobei ich dafür kein Plugin habe, sondern ein paar Zeilen Code, die ich gerne hier reinstellen kann, falls Interesse besteht. Da passiert aber nicht viel anderes, als das mittels JS ein Formular-Objekt erstellt wird und dort dann eben die Datei als "files[]" angefügt wird. |
AW: TWebModule und Multipart
@Bbommel:
das mit dem RawContent deckt mit mit meinem RawContent, wenn ich den enctype verwende. Jedoch wundert es mich, dass genau dann die Unit Web.ReqMulti nicht verwendet wird (Habe entsprechende Haltepunkte gesetzt, die dann nicht angelaufen werden). Die Filedaten sind aber definitiv in RawContent vorhanden, das kann man ja schnell sehen. @Rolf Frei: Ja, das mit dem .php ist vielleicht etwas unglücklich ;-) Danke für den Tipp, ich werde das wohl auch erst mal so umsetzen. Da aber mit den Bild auch noch Metainformationen gesendet werden sollen, hätte ich das zwar schon gerne in einem Request, aber dazu kann man sich ja einen Workaround bauen. @all Was ich jedoch nicht verstehe: Wenn ich die Übertragung so aufteilen muss, damit es funktioniert, also den enctype weglasse, wir die ReqMulti angesprochen, liefert aber immer IsMultipartForm=False zurück. Wenn ich die Übertragung nicht aufteile muss ich den enctype verwenden, aber die ReqMulti wird nie angesprochen. Wofür wäre dann die ReqMulti da? Das in der ReqMulti genau diese RawContent geparst wird, kann man ja im Code schon direkt erkennen. @Bbommel: Ich werde mein Input-Element mal Files nennen, aber ich glaube nicht, dass es daran liegt. |
AW: TWebModule und Multipart
Zitat:
Code:
im Namen.
[]
|
AW: TWebModule und Multipart
Habe das nun mit einer simplen Form getestet und das funktioniert bei mir einwandfrei.
Code:
Die Fielupload Action sieht so aus:
<form method="POST" action="fileupload" name="MyForm" enctype="multipart/form-data">
<input type="file" name="filename" value=""> </form>
Delphi-Quellcode:
Nach Auswahl einer Datei und Senden des Formulars ist die Datei in meinem Uploadordner vorhanden. Das Ganze habe ich aber mit einer CGI-EXE und IIS getestet. Da ein Standalone Server glaube ich aber auf Indy basiert, könnte es eventuell damit zusammen hängen, dass das da nicht geht. Ist aber reinen Spekulation. Versuche das doch bei dir auch mal mit einer CGI-EXE (oder ISAPI-DLL wenn es komplizierter sein soll) und IIS anstelle eines eigenen Servers.
procedure TESWebModule.waFileUploadAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); begin if Request.Files.Count > 0 then begin with TFileStream.Create(FUploadDir + Request.Files[0].FileName, fmCreate) do try CopyFrom(Request.Files[0].Stream, Request.Files[0].Stream.Size); finally Free; end; end; end; @Bbommel Nein das [] ist nicht nötig, das hängt mit dem Server zusammen und ist da unter Umständen nötig, damit der Server mehrere Files verabreiten kann (z.B. PHP). Siehe auch hier: ![]() In Firefox wird das Bild mit diesen Angaben geschickt und das funktioniert einwandfrei:
Code:
-----------------------------3165091648410499962260122359
Content-Disposition: form-data; name="filename"; filename="bruch0002.JPG" Content-Type: image/jpeg Binäre Daten .... |
AW: TWebModule und Multipart
Ein Versuch ist das mit dem CGI vielleicht wert, aber bei mir läuft der Server auch immer als Standalone-Anwendung und zumindest bei lokalen Tests auch ohne irgendwas dazwischen und es funktioniert ja. Insofern kommen die Daten ja - ob mit oder ohne Indy - offenbar eigentlich sauber im WebModule an.
|
AW: TWebModule und Multipart
Danke für eure Hilfe.
ich habe jetzt noch mal eine ganz neues Projekt aufgesetzt (als Standalone), ReqMulti hinzugefügt, und der Fileupload funktioniert schon mal. Insofern muss ich wohl suchen, warum das in der eignetlichen Anwendung nicht der Fall ist. Zwei Fragen habe ich aber noch. 1. Jetzt Frage ich ab, ob Request.Files.Count>0 , um festzustellen ob es eine Multipart-Response ist. Gibt es dafür noch einen eleganteren Weg, oder ist das schon die einige Methode? 2. Solange als Method="post" übertragen wird, kann ich zwar die Files abfragen, aber meine QueryFields sind immer leer (obwohl ich alle Parameter im Content finden kann). Erst wenn ich als Method Get verwende, wird QueryFields auch gefüllt. Es wäre aber schon gut, wenn ich im Post auch die anderen Felder, die das Web-Formular mit überträgt (und sie sind doch im Content enthalten), auch auslesen könnte. Ich könnte mir zwar einen eigenen Parser schreiben, aber sollte das nicht direkt funktionieren? Hier mal die Action im Webmodule:
Delphi-Quellcode:
Und hier mal die html-seite mit der ich testweise den Upload mache:
procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); var datatype: string; content: string; begin Response.Content := '<html>' + '<head><title>Webserver-Anwendung</title></head>' + '<body>Webserver-Anwendung</body>' + '</html>'; if Request.Files.Count > 0 then begin with TFileStream.Create('C:\OrderApp\' + Request.Files[0].FileName, fmCreate) do try CopyFrom(Request.Files[0].Stream, Request.Files[0].Stream.Size); finally Free; end; end; with TStreamWriter.Create(TFileStream.Create('C:\OrderApp\Query.txt', fmCreate), TEncoding.UTF8) do try content:=Request.Content; datatype:=Request.QueryFields.Values['DataType']; Write(datatype); Write(content); Flush; Close; finally BaseStream.Free; Free(); end; end;
Code:
<html>
<head> <meta charset="utf8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <form id="myForm" action="http://localhost:8443/senddata.php" method="post" enctype="multipart/form-data"> <input type="text" name="DataType" value="fileupload"> <input type="file" size="120" name="myfile"> <input type="text" size="20" name="mimetype" value="image/bmp"> <input type="submit" value="upload"> </form> </body> </html> |
AW: TWebModule und Multipart
Du kannst Request.ContentType abfragen aber brauchst du eigentlich nicht, da Files.Count in deinem Fall ausreicht.
Du hast aber in deinem Code noch eine grossen Fehler. Du nutzt das Request.QueryFields für den Zugriff der gesendeten Formaulardaten. In deinem Fall wirst du da nie etwas drin haben. QueryFields ist nur bei einem Formular mit der method="GET" oder einem Aufruf über eine URL abgefüllt. Bei einem Formular mit method="POST" sind die Formulardaten im Request.ContentFields abgefüllt. Der Unterschied von GET und POST ist der, dass beim GET die Daten per URL-Parameter übergeben werden und es somit Längenbeschränkungen gibt. Dieses sollte man in Formen eher nicht nutzen, insbesondere in deinem Fall wo Filedaten übertragen werden. Bei einem POST werden die Daten im Body (Content) der Anfrage übergeben und sind daher in der Grösse praktisch unbeschränkt. Bei GET Anfragen musst du QueryFields nutzen und bei POST ContentFields.
Delphi-Quellcode:
Ausserdem scheinst du eine Eingabe auf der Form zu haben, die den Dateityp vom Anwender verlangt. Das solltest du nicht so machen, denn der notrmale Anwender wird das kaum richtig eingeben. Die nötige Info steht eigentlich bereits im Request.Files[x].ContentType.
datatype:=Request.QueryFields.Values['DataType'];
müsste so sein: datatype:=Request.ContentFields.Values['DataType']; |
AW: TWebModule und Multipart
Vielen Dank für die ausführliche Antwort. Das mit QueryFields und ContentFields wußte ich nicht.
Das mit dem Dateitype als Eingabe auf dem Forumlar war nur zum rumtesten. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:34 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz