Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.182 Beiträge
 
Delphi 12 Athens
 
#1

DataSnap - Zugriff von WebProjekt

  Alt 29. Jun 2020, 13:58
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:
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"]}
oder
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:
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@&#381;8|³=&#8364;&#8218;n¶&#8211;&#8364;ÑÅ¿ï÷"2²*«ºÉ^&#8224;Ò¡Y[.±¼X23øõxøûñðõÜß4N½C7ø©O&#402;ïð&#732;¦.O}î~û÷ñðýñðëñðòåxøóg×Íýìº/ÿ9~ø±sÝ¿&#381;&#8225;&#8249;ë~ûéxHSî&#8225;Ô
Cî3ÚàÛ_&#339;&#8249;Ù¹ðì&#339;ÇÕGü\¹ò&#382;¿¿ñÔ}ùùxxÅ7Ì&#8220;Sï&#8217;ÍãÆ&#8482;ðÃu\ÞÛ¼r½k&#382;ú<*çq ;&#402;îð#Cä#Ý5vô½6v!+òðéß|×\~î&#8225;ÁæyQf¦&#8225;¸&#338;¹J
...
GET-Abrufe funktionieren erstmal.

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:
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"}
also
Code:
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"]}
oder
Code:
...
{"filename":"rechnung\\1192__.pdf", "stream":"123456789"}
oder mit filename in der URI
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 ;
51fxxxxx ist die DataSnapServer150.bpl

[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
[/EDIT]


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:
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;
und der automatisch generierte Code dazu
Delphi-Quellcode:
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;
POST ist also richtig
und beim Debuggen von FWriteFileCommand.Execute ist zu erkennen, dass es als zwei Parameter in JASON verpackt wird.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (29. Jun 2020 um 16:26 Uhr)
  Mit Zitat antworten Zitat