Upload the file to the DataSnap REST server via TStream

I built a DataSnap REST server using Delphi XE2, and I added a server method for uploading files via TStream:

function TServerMethods.updateUploadFile(sFilename: string; UploadStream: TStream): string; 

I want to be able to call this from several different clients (Android, iOS, etc.), and I tested this method with various REST clients such as Postman (Chrome plugin). However, so far I cannot get it to accept content for the HTTP POST body. Whenever I send a POST command, I always get the following response:

 {"error":"Message content is not a valid JSON value."} 

I tried using different Content-Type settings, but nothing works. Looks like DataSnap is insisting that the content is JSON? I tried pasting some valid JSON into the content area, but this also gave the same answer.

Has anyone successfully used TStream as an input parameter to a DataSnap server method? Should I do it differently? I used TStream as an output parameter to download files many times and it works well, this is my first attempt to download.

UPDATE

I made a quick Delphi DataSnap client to test the uploadFile server method, and all this works fine. Then I used Fiddler to check the POST command that the Delphi client uses to send the TStream in the content body, and noticed that this is a JSON array of integers (bytes), for example. [37,80,68,70,45,49,46,51,13,10] . So I can see that I can change my Android / iOS clients to convert binary data to this byte array format before POSTING, but this is an overhead that I could get around. If the DataSnap passes the source binary when the TStream is a return parameter, why can't it pass the source binary as an input parameter?

+1
source share
1 answer

It seems that when adding content data to the request body in the POST command, the DataSnap server insists that this data is always JSON. This is why when using TStream as an input parameter, the stream data is converted to a JSON array of integers (bytes) by the Delphi DataSnap client. This format is very inefficient in size, since up to 3 digits per byte, plus a comma, the size of the downloaded data can grow by as much as 4 times.

Instead, I did this to encode the data to be loaded into Base64. Now my server method is as follows:

 function TServerMethods.updateUploadFile(sFilename: string; Base64Data: TJSONObject): string; 

Note that I am wrapping a Base64 string in a TJSONObject. This is because if you just specify the String type, the Delphi DataSnap client will call the method with GET and try to put the entire Base64 string in the URL path, causing the "Connection Closed Gracefully" error. Using TJSONObject forces DataSnap to use POST and put data in the content body. The JSON object is passed as one paired object:

 {"UploadedData":"JVBERi0xLjMNCiXi48B5SiWGTK3PaY.........."} 

Thus, the size of the downloaded data is much smaller and faster transferred. I would still prefer to be able to transfer raw data to the content body, but DataSnap does not allow this.

+3
source

Source: https://habr.com/ru/post/1263339/


All Articles