8

当您在 Delphi REST 服务器中使用文件流对象返回图像时,它不会显示在浏览器中。这是一个返回图像的示例方法:

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

2 回答 2

17

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

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

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

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

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

给定的示例变为:

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

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

于 2012-12-14T13:02:42.870 回答
3

我也发现了这个问题,试图从 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 代码中分配的内容处置和内容类型未显示。

于 2014-09-09T21:35:39.647 回答