【问题标题】:Return an image from a Delphi REST server and show it in a browser从 Delphi REST 服务器返回图像并在浏览器中显示
【发布时间】:2012-12-14 13:02:42
【问题描述】:

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

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

【问题讨论】:

    标签: delphi datasnap


    【解决方案1】:

    问题在于 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;
    

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

    【讨论】:

      【解决方案2】:

      我在尝试从 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 ...';
      

      发现对我有用的解决方法是:

      在服务器方法单元中

      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 代码中分配的 Content-disposition 和 content-type 未显示。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多