从Delphi REST服务器返回一个图像并在浏览器中显示它

时间:2012-12-14 13:02:43

标签: delphi datasnap

在Delphi rest服务器中使用文件流对象返回图像时,它不会显示在浏览器中。以下是返回图像的示例方法:

function TServerClass.Image: TFileStream;
begin
  Result := TFileStream.Create('pathtofile\image.png', fmOpenRead or fmShareDenyNone);
end;

2 个答案:

答案 0 :(得分:17)

问题是Delphi REST服务器总是将内容类型设置为text / html。当您发送其他类型的内容时,这会混淆浏览器。这是一个错误,因为大多数响应都是json,这意味着最合理的默认内容类型应该是application / json。

幸运的是,有一种方法可以从服务器方法中覆盖内容类型。

您需要将Data.DBXPlatform添加到实现的使用列表中。

此单元包含函数GetInvocationMetadata,可以访问正在构建的响应。它返回一个TDSInvocationMetadata对象,其中varius其他有用的属性具有ResponseContentType属性。

设置此属性会覆盖方法在http响应中返回的Content-Type标头。

给定的例子变为:

function TServerClass.Image: TFileStream;
begin
  Result := TFileStream.Create('pathtofile\image.png', fmOpenRead or fmShareDenyNone);
  GetInvocationMetadata.ResponseContentType := 'image/png';
end;

现在结果图像将在浏览器中正确显示。

答案 1 :(得分:1)

我发现这个问题也试图从DataSnap REST服务器(Delphi XE3)下载不同的文件类型(png,pdf,xlsx,docx等)到JavaScript Web客户端。 有些浏览器(例如:FireFox)无论如何都会采取正确的行动,但不是全部。没有正确的内容类型,Internet Explorer无法识别下载文件的正确操作。 @Anders解决方案最初似乎对我有用,因为我正在使用PDF和Firefox。 但是,当我在IE(和其他人)上测试并使用不同的扩展时,文件无法识别。使用FireBug我已经看到Content-Type始终是“text / html”而不是使用

分配的那个
GetInvocationMetadata.ResponseContentType := '...my assigned content type ...';

为我工作的解决方法是:

在ServerMethodsUnit

var
   ContentTypeHeaderToUse: string;  // Global variable

TServerMethods1.GetFile(params: JSON):TStream;
begin
   .... processing ....
   ContentTypeHeaderToUse := '...' (assign correct content type).
end;

在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;

我也使用了类似的解决方案来分配Content-Disposition。这是一个有用的标题键,用于将文件名设置为下载和附件/内联模式。 有了这个,代码是:

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;

将ContentDispositionHeaderToUse分配到服务器方法实现中。

修改

此解决方法在启用了数据压缩的IIS上的ISAPI DLL中不起作用! 没有数据压缩(本地调试IIS),响应头是:

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

但是在启用了生产的情况下,IIS会响应:

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

DataSnap代码中分配的内容处置和内容类型未显示。