|
Antwort |
Online
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.054 Beiträge Delphi 12 Athens |
#1
Falls jemand weiß wie man da mit JavaScript Binärdaten überträgt, wäre es schön zu wissen,
denn die bestehende Serverstruktur weiterverwenden zu können, für die neue zusätzliche Webanwendung, das wäre doch zu praktisch. * Dokumente abrufen und anzeigen (das Ginge) * Foto machen oder Datei einlesen und übertragen (das knallt) Also, damals vor vielen Jahren einen DataSnap-Server implementiert und bissl angepasst. Wir haben noch eine Zwischenschicht im DataSnap drin, welche beim Empfänger (Client und Server) die TStreams von dem blöden DataSnap-Stream in ein TMemoryStream umkopiert, weil viele Dinge mit dem Size=-1 nicht klar kommen, was bei größeren Streams ankommt, wenn DataSnap die Daten beim Auslesen stückweise nachlädt. Und auch TDataSets hatten wir damals nochmal überarbeitet, weil es bei größeren TEXTen Probleme gab, im Zusammenhang mit DevExpressGrids und dessen DataController. (TEXT in VARCHAR konvertiert, vor Übergabe in dem DBXDataSetStreamingzeugs, bzw. den Code kopiert und da die Typen ausgetauscht). Das lief bisher problemlos binär, also via TCP/IP (TDSTCPServerTransport2), bzw. intern mit dbExpress, und nun hatte noch den TDSHTTPService nachgerüstet. Aber dort habe ich nun Probleme beim Abruf. Erstmal wird die AuthentificationMethode doppelt aufgerufen und beim zweiten Mal mit NIL im Parameter (ist bekannt, denn viele hatten das Problem schon), was bissl blöd ist, wenn man auf den Parameter zugreift, um darin Nutzername und Passwort zu prüfen. (gut, da der erste Durchlauf ausreicht, überspring ich das einfach ... if not assigned then exit) Schlimmer ist aber, dass ich ums verrecken nicht alle Funktionen aufgerufen bekomme, vorallem da nicht wo in TStream reingegeben werden soll. [EDIT] Da hing wohl ein Haltepunkt etwas. Grade nochmal alles ohne Eurekalog kompiliert, und nun gesehen dass unsere TDSFileMethods.WriteFile erfolgreich aufgerufen und ausgeführt wird, aber nach dem END; der Methode knallt es dann irgendwo. [/EDIT] * Danke erstmal an Eurekalog, dass ihr einem ständig beim Debuggen das Leben erschwert. * nach Loswerden des Mistdings nun "irgendwo" die Fehlerstelle in der DataSnapServer150.bpl verordet, aber k.A. warum. (ja, der Umstieg auf 10.2 ähhh 10.3 10.4 ist schon geplant) Zuerst hab ich mir mal schnell eine Clientanwendung generieren lassen und wollte mir im Server das Protokoll loggen, um zu sehen was wie übergeben werden muß, aber leider knallt es jetzt schon. Beim Debuggen und aus dem generierten Client ist zu erkennen, dass "leider" der Stream als JSON via HTTP-POST übergeben werden muß. Gut, unser Webentwickler wäre damit schon zufrieden, falls ich es hinbekomm dass es funktioniert, und wenn man rausbekommt wie die Binärdaten da codiert werden müssen. Gefragt hatte er aber auch zuerst, ob wir z.b. auch MultiPart-POSTs als über einen REST-Serverannehmen können, wobei mir dann erstmal einfiel, dass DataSnap auch RESTful ist und so wollte ich erstmal schauen was damit geht, weil der schon da ist. Das Format des JSON, bzw. die zwei Möglichen der Parameterübergabe sind teilweise aus der Doku zu entnehmen, jedenfalls das grundlegende Format, aber nicht der einzelnen Datentypen. http://docwiki.embarcadero.com/RADSt...gen_entwickeln http://docwiki.embarcadero.com/RADSt...nd_Architektur http://docwiki.embarcadero.com/RADSt.../DataSnap-REST http://docwiki.embarcadero.com/RADSt...chtenprotokoll http://docwiki.embarcadero.com/RADSt...ientbibliothek * Hab ich beide probiert, es knallte, also hab ich den TestClient neu generieren lassen. SO, hier die 3 Testfunktionen des DataSnap-Servers: [DELPHI]function TDSServerMethods.ReverseString(S: String): String; function TDSFileMethods.ReadFile(Filename: String): TStream; procedure TDSFileMethods.WriteFile(Filename: String; Stream: TStream);[DELPHI] Und Letztere knallt leider. Wenn nichts geht, muß ich wohl selbst codieren (z.B. Base64) und es als "String" übergeben lassen. Über https://apitester.com/ bissl rumprobiert:
Code:
GET /DataSnap/REST/TDSServerMethods/ReverseString/ABC12345 HTTP/1.1
Host: *****:8080 Accept: */* User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; http://rigor.com) Authorization: Basic *****
Code:
oder
HTTP/1.1 200 OK
Connection: close Content-Type: text/html; charset=ISO-8859-1 Content-Length: 23 Pragma: dssession=305680.375499.525712,dssessionexpires=1200000 Server: DatasnapHTTPService/2011 {"result":["54321CBA"]}
Code:
GET /DataSnap/REST/TDSFileMethods/ReadFile/rechnung\1192.pdf HTTP/1.1
Host: pg.prodat-erp.de:8080 Accept: */* User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; http://rigor.com) Authorization: Basic *****
Code:
GET-Abrufe funktionieren erstmal.
HTTP/1.1 200 OK
Connection: close Content-Type: text/html; charset=ISO-8859-1 Content-Length: 194106 Pragma: dssession=407731.981971.840684,dssessionexpires=1200000 Server: DatasnapHTTPService/2011 %PDF-1.7 %âãÏÓ 2 0 obj <</Length 3532/Filter/FlateDecode>> stream xÅ[Én$ǽ7ÐÿPg,çZ`4@Ž8|³=€‚n¶–€ÑÅ¿ï÷"2²*«ºÉ^†Ò¡Y[.±¼X23øõxøûñðõÜß4N½C7ø©Oƒïð˜¦.O}î~û÷ñðýñðëñðòåxøóg×Íýìº/ÿ9~ø±sÝ¿Ž‡‹ë~ûéxHSî‡Ô Cî3ÚàÛ_œ‹Ù¹ðìœÇÕGü\¹òž¿¿ñÔ}ùùxxÅ7Ì“Sï’ÍãÆ™ðÃu\ÞÛ¼r½kžú<*çq ;ƒîð#Cä#Ý5vô½6v!+òðéß|×\~î‡ÁæyQf¦‡¸Œ¹J ... Und ja, bemerkenswert ist, dass DataSnap immer von "text/html" redet, egal ob es REST/JSON oder Binärdaten ausliefert. Im Gegenzug ist es auch vollkommen egal, was ich als Content-Type übergeben, es wird immer als JSON interpretiert, denn wenn ich versuche es wie beim Abruf binär zu übergeben, dann
Code:
POST /DataSnap/REST/TDSFileMethods/%22WriteFile%22/rechnung%5C1192.pdf HTTP/1.1
Host: pg.prodat-erp.de:8080 Accept: */* User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; [url]http://rigor.com[/url]) Authorization: Basic ***** Content-Type: application/octet-stream Content-Length: 194106 %PDF-1.7 %âãÏÓ 2 0 obj ...
Code:
also
HTTP/1.1 500 Interner Server-Fehler
Connection: close Content-Type: text/html; charset=ISO-8859-1 Content-Length: 93 Pragma: dssession=982145.594458.865431,dssessionexpires=1200000 Server: DatasnapHTTPService/2011 {"error":"JSON-Werteingabe %PDF-1.7.... kann nicht in TDBXTypes.UNKNOWN(33) konvertiert werden"}
Code:
oder
POST /DataSnap/REST/TDSFileMethods HTTP/1.1
Host: pg.prodat-erp.de:8080 Accept: */* User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; http://rigor.com) Authorization: Basic ***** Content-Length: 88 Content-Type: application/x-www-form-urlencoded {"_parameters":["rechnung\\1192__.pdf", "123456789"]}
Code:
oder mit filename in der URI
...
{"filename":"rechnung\\1192__.pdf", "stream":"123456789"}
Code:
...
{"stream":"123456789"}
Code:
HTTP/1.1 500 Interner Server-Fehler
Connection: close Content-Type: text/html; charset=ISO-8859-1 Content-Length: 89 Pragma: dssession=144988.358193.280590,dssessionexpires=1200000 Server: DatasnapHTTPService/2011 Zugriffsverletzung bei Adresse 5003A116 in Modul 'rtl150.bpl'. Lesen von Adresse 00000001
Zitat:
:74ddc562 KERNELBASE.RaiseException + 0x62
:5003a0d5 TObject.FreeInstance + $11 :5003a0d5 TObject.FreeInstance + $11 :51fa5d92 Generics + $445D92 :51fa1169 Generics + $441169 :51fa1cb8 Generics + $441CB8 :51ff2081 Generics + $492081 :50bb76c8 TIdCustomHTTPServer.DoCommandGet + $20 :50bb8639 TIdCustomHTTPServer.DoExecute + $591 :50ab794a TIdContext.Run + $12 :500acc4d ThreadProc + $45 :5003bf42 ThreadWrapper + $2A :779f62c4 KERNEL32.BaseThreadInitThunk + 0x24 :77d30969 ; :77d30934 ; [EDIT] Also unsere Methode ist durchgelaufen und nach dem END hab ich mich nun mühsam mit F7/F8 durchgekämpft. Im zweiten oder dritten Generis+xxx (DataSnapServer150.bpl) knallt es dann, scheinbar am Ende einer Methode, beim Freigeben eines "Records", im zweiten Eintrag, bei der Speicherfreigabe. EInvalidPointer (Ungültige Zeigeroperation) oft gefolgt von zwei oder drei dutzend Indy- und DBX-Exceptions.
Zitat:
:51fe980a TDSServerMethod.Invoke + $1E2
:51fe9d25 TDSServerMethodCommandHandler.DbxExecute + $19D :51fe944b TDSServerConnectionHandler.DbxExecute + $27 :51fe784d TDSServerCommand.DerivedExecuteUpdate + $5 :51f78ac6 Generics + $418AC6 :51f787c1 Generics + $4187C1 :51f7929c Generics + $41929C :51f794b4 Generics + $4194B4 :51fa1050 Generics + $441050 :51fa1cb8 Generics + $441CB8 :51ff2081 Generics + $492081 :50bb76c8 TIdCustomHTTPServer.DoCommandGet + $20 Im Moment weiß ich einfach nicht mehr weiter. Die Methoden mit dem TCPIP-Client funktionieren seit Jahren, aber über den HTTP-TunnelService raucht ein Teil grandios ab. Aus dem neuen Testclient
Delphi-Quellcode:
und der automatisch generierte Code dazu
procedure TForm1.Button1Click(Sender: TObject);
var X: TStream; S: string; begin { S := ClientModule1.DSServerMethodsClient.ReverseString('abc123'); if S = '321abc' then ; X := ClientModule1.DSFileMethodsClient.ReadFile('rechnung\1192.pdf'); if X.Size > 0 then ; X.Free; } S := '12345'; X := TMemoryStream.Create; X.Write(S[1], 10); X.Position := 0; ClientModule1.DSFileMethodsClient.WriteFile('rechnung\1192.pdf', X); X.Free; end;
Delphi-Quellcode:
POST ist also richtig
procedure TDSFileMethodsClient.WriteFile(Filename: string; Stream: TStream);
begin if FWriteFileCommand = nil then begin FWriteFileCommand := FConnection.CreateCommand; FWriteFileCommand.RequestType := 'POST'; FWriteFileCommand.Text := 'TDSFileMethods."WriteFile"'; FWriteFileCommand.Prepare(TDSFileMethods_WriteFile); end; FWriteFileCommand.Parameters[0].Value.SetWideString(Filename); FWriteFileCommand.Parameters[1].Value.SetStream(Stream, FInstanceOwner); FWriteFileCommand.Execute; end; und beim Debuggen von FWriteFileCommand.Execute ist zu erkennen, dass es als zwei Parameter in JASON verpackt wird.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat, wird PoSex im Delphi viel seltener praktiziert. Geändert von himitsu (29. Jun 2020 um 17:26 Uhr) |
Zitat |
Online
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.054 Beiträge Delphi 12 Athens |
#2
So, nach paar Tagen genervter Suche, endlich eine Lösung.
Ich hab mich nun mühevoll durch das Senden des DataSnap-HTTP/REST-Clienten gekämpft und geschaut was gesendet wird. Ja, es gibt eine nette Trace-Methode im Server, wo man das Protokoll loggen kann, allerdings wird die erst NACH der Verarbeitung aufgerufen, wo man dann Request und Response einsehen kann, aber da es schon vorher knallt und abraucht ......... TDSRestCommand.Execute ExecuteCommand (DSClientRest) ExecuteRequest (DSClientRest) LParametersToSendInContent:= ExecuteRequest> ParameterToJSon TDBXJSONTools.StreamToJSON Dabei ensteht ein JSON-Array mit sehr vielen Values/Integern pro Byte, locker 3 bis 4 Mal so viele Daten wie die Datei groß ist. procedure TDSFileMethods.WriteFile(Filename: String; Stream: TStream);
Zitat von 10 Byte-Datei:
POST /DataSnap/REST/TDSFileMethods/%22WriteFile%22/rechnung%5C1192.pdf HTTP/1.1
Host: *** Authorization: Basic *** Accept: application/JSON Content-Type: text/plain;charset=UTF-8 If-Modified-Since: Mon, 1 Oct 1990 05:00:00 GMT Content-Length: 26 [0,1,2,3,4,5,6,32,128,255] Mit einem Delphi-Client könnte ich meine Lösung nicht umsetzen, da DataSnap alle String-Parameter ohne Längenprüfung in die URL einbaut (in XE) und nur Tabellen/Streams/Json als JSON via POST sendet (siehe ExecuteRequest und IsUrlParameter in DSClientRest), aber zum Glück kann man das bei manuellem REST-Aufruf das anpassen (eine beliebige Anzahl der Parameter in der URL und ab beliebiger Quelle geht's weiter im JSON-Request). Wichtig ist aber dass man Accept und Content-Type nicht vergisst, denn so wie im Response der Content-Type totaler Schwachsinn ist, darf man ihm im Request aber nicht vergessen, sonst werden die POST-Daten zwar zwangsweise als JSON entgegen genommen (oder es knallt) aber dann einfach still und heimlich ignoriert (POST-Parameter bleiben leer und TStream ist nil). Hab das mal mit ReverseString ausprobiert function TDSServerMethods.ReverseString(S: String): String;
Zitat:
GET /DataSnap/REST/TDSServerMethods/ReverseString/ABC12345 HTTP/1.1
Host: ***** Accept: */* Authorization: Basic *****
Zitat:
POST /DataSnap/REST/TDSFileMethods/%22ReverseString%22 HTTP/1.1
Host: ***** Authorization: Basic ***** Accept: application/JSON Content-Type: text/plain;charset=UTF-8 If-Modified-Since: Mon, 1 Oct 1990 05:00:00 GMT Content-Length: 29 {"_parameters":["123456789"]}
Zitat:
{"result":["987654321"]}
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat, wird PoSex im Delphi viel seltener praktiziert. Geändert von himitsu (30. Jun 2020 um 19:13 Uhr) |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |