When you return an image using a file stream object in a Delphi rest server, it will not display in a browser. Here is an example method that returns an image:
function TServerClass.Image: TFileStream;
begin
Result := TFileStream.Create('pathtofile\image.png', fmOpenRead or fmShareDenyNone);
end;
The problem is that Delphi REST server always sets the content type to text/html. This confuses the browser when you send other types of content. It is a bug, since most responses are json, which means the most sensible default content type should be application/json.
Fortunately there is a way to override the content type from within the server method.
You need to add Data.DBXPlatform to the uses list of your implementation.
This unit contains the function GetInvocationMetadata, which gives access to the response that is being build. It returns a TDSInvocationMetadata object which among varius other useful properties has the ResponseContentType property.
Setting this property overrides the Content-Type header that the method returns in the http response.
The given example becomes:
function TServerClass.Image: TFileStream;
begin
Result := TFileStream.Create('pathtofile\image.png', fmOpenRead or fmShareDenyNone);
GetInvocationMetadata.ResponseContentType := 'image/png';
end;
Now the result image will be displayed properly in the browser.
I've found this problem too trying to download different file types (png, pdf, xlsx, docx, etc...) from DataSnap REST server (Delphi XE3) to a JavaScript web client.
Some browsers (es.: FireFox) will take correct action anyway, but not all. Internet Explorer doesn't recognize the proper action for the downloaded file without correct content-type.
The @Anders solution initially seems to work for me because I was working with PDF and Firefox.
But when I've tested on IE (and others) and with different extensions, the files where not recognised. Using FireBug I've seen that Content-Type was always "text/html" and not the assigned one using
GetInvocationMetadata.ResponseContentType := '...my assigned content type ...';
The workaround found working for me is:
In ServerMethodsUnit
var
ContentTypeHeaderToUse: string; // Global variable
TServerMethods1.GetFile(params: JSON):TStream;
begin
.... processing ....
ContentTypeHeaderToUse := '...' (assign correct content type).
end;
In WebModuleUnit
procedure TWebModule1.WebModuleAfterDispatch(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
if ContentTypeHeaderToUse<>'' then begin
Response.ContentType := ContentTypeHeaderToUse;
ContentTypeHeaderToUse := ''; // Reset global variable
end;
end;
I used a similar solution for assigning Content-Disposition too. This is a useful header key in order to set file name to download and attachment/inline mode.
With this one the code is:
procedure TWebModule1.WebModuleAfterDispatch(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
if ContentDispositionHeaderToUse<>'' then begin
Response.SetCustomHeader('content-disposition',ContentDispositionHeaderToUse);
ContentDispositionHeaderToUse := '';
end;
if ContentTypeHeaderToUse<>'' then begin
Response.ContentType := ContentTypeHeaderToUse;
ContentTypeHeaderToUse := '';
end;
end;
Assign ContentDispositionHeaderToUse into the server methods implementation.
EDIT
This workaround doesn't work in ISAPI DLL on IIS with data compression enabled!
With no data compressione (local debuggin IIS) the response header is:
Connection close
Content-Disposition inline; filename="Privacy-0.rtf.pdf"
Content-Length 150205
Content-Type application/pdf; charset=ISO-8859-1
Pragma dssession=28177.371935.39223,dssessionexpires=1200000
but with production enabled IIS the response comes with:
Content-Encoding gzip
Content-Length 11663
Content-Type text/html
Date Thu, 11 Sep 2014 21:56:43 GMT
Pragma dssession=682384.52215.879906,dssessionexpires=1200000
Server Microsoft-IIS/7.5
Vary Accept-Encoding
X-Powered-By ASP.NET
Content-disposition and content-type assigned in DataSnap code are not surfaced.