REST風APIをCakePHP(2.x系)で作ってて、IE9で画像をアップロードした結果のレスポンスがapplication/jsonだと、JavaScriptが受け取れずにダウンロードしようとする。
これを回避した話。
経緯
FormDataが使えない環境では、iframeにformのDOM構成を作って、ファイルをPOSTする方法がとって対応している模様。
IE9ではapplication/jsonが定義されていないのか解釈できず、APIのレスポンスをファイルとしてダウンロードしようとする。
IE9の場合はapplication/jsonではなく、text/plainで返せばJavaScriptで処理できる
状況
ここに従って、CakePHPでREST風APIを作っていました。
REST — CakePHP Cookbook 2.x ドキュメント
app/Config/routes.php
でこんな風に指定し、
Router::mapResources('recipes'); Router::parseExtensions('json');
あと、Controller/RecipesController.php
でRequestHandler
コンポーネントを指定。
class RecipesController extends AppController { public $components = array('RequestHandler'); ...
この状態でrecipes.jsonにアクセスするとレスポンスのContent-Typeがapplication/jsonとなります。
parseExtensions()
とRequestHandler
がリクエストの形からフォーマットをJSONと判断します。
レスポンスのビューまでを一括で担当し、JSONとしてレスポンスを返してくれます。
このためJSONでやりとりしながらContent-Typeのみtext/plainにするのはそのままではできませんでした。
解決策
最終的には、拡張子txtでやりとりし、レスポンスの中身はJSONにすることで対応しました。
- *.txtでのアクセスを許可する
Router::mapResources('recipes'); Router::parseExtensions('json', 'txt');
... class TxtViews extends Views{ ... $controller->response->type('txt'); ...
これで、呼ぶ方も.txtで呼ばないといけなくなりましたが、なんとかなった状態です。
以下試して反映されなかったもの
JsonViewsが上書きしているので、Content-Typeを変更する手段はことごとくうまくいきませんでした。
header('Content-Type: text/plain; charset=utf8;') $this->RequestHandler->type('txt'); ...