Delphiレストサーバーでファイルストリームオブジェクトを使用して画像を返す場合、ブラウザには表示されません。画像を返すメソッドの例を次に示します。
function TServerClass.Image: TFileStream;
begin
Result := TFileStream.Create('pathtofile\image.png', fmOpenRead or fmShareDenyNone);
end;
問題は、DelphiRESTサーバーが常にコンテンツタイプを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;
これで、結果の画像がブラウザに正しく表示されます。
DataSnap RESTサーバー(Delphi XE3)からJavaScript Webクライアントにさまざまなファイルタイプ(png、pdf、xlsx、docxなど)をダウンロードしようとしても、この問題が見つかりました。一部のブラウザ(例: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のISAPIDLLでは機能しません。データ圧縮なし(ローカルデバッグIISIS)の場合、応答ヘッダーは次のようになります。
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コードで割り当てられたコンテンツの性質とコンテンツタイプは表示されません。