Hatena::ブログ(Diary)

on the center line.

2008-10-03

XMLHttpRequestオブジェクトでリダイレクトをハンドリングする方法

| 10:05

以前に、同じタイトルのエントリを書いたのですが、それよりもスマートなやり方がわかったので、書いておきます。

やりたいことについては前のエントリで書いたとおり。

  1. XMLHttpRequestで送ったリクエストが、サーバで認証エラー(セッションタイムアウトなど)となる
  2. このときサーバは認証エラー(=401)を返すのではなく、ログインページへのリダイレクトを返す
  3. クライアントXMLHttpRequest)は、リダイレクト応答をうけとり、自動的にリダイレクト先を追跡する
  4. 結果、クライアントログインページのHTMLを取得する(このときステータスコード=200)
  5. しかし、そもそもクライアントJSON形式のデータを期待しているためスクリプトエラーとなる

前のエントリでは、XMLHttpRequestでレスポンスヘッダが使えることに着目して、"Content-Type"ヘッダが"text/html"だったらページを強制的に遷移させる方法でした。しかし、この方法は「"Content-Type"ヘッダが"text/html"である正常なレスポンス」があったら使えません。そこで以下の方法を思いつきました。4. および 6. のところが今回紹介する方法になります。

  1. XMLHttpRequestで送ったリクエストが、サーバで認証エラー(セッションタイムアウトなど)となる
  2. このときサーバは認証エラー(=401)を返すのではなく、ログインページへのリダイレクトを返す
  3. クライアントXMLHttpRequest)は、リダイレクト応答をうけとり、自動的にリダイレクト先を追跡する
  4. ログインページでは、レスポンスヘッダに "AjaxRedirect: /Login.jsp" を追加する
  5. 結果、クライアントログインページのHTMLを取得する(このときステータスコード=200)
  6. クラインアンは、レスポンスヘッダをチェックし、"AjaxRedirect" ヘッダが設定されているので、その値のURLを追跡する

以上で、XMLHttpRequestを使ったリダイレクトの完成。サンプルコードも載せておきます。

<%
response.setHeader("AjaxRedirect", request.getContextPath() + "/Login.jsp");
%>
httpRequest.onreadystatechange = function() {
  if (httpRequest.readyState == 4 && httpRequest.status == 200) {
    var redctUrl = httpRequest.getResponseHeader("AjaxRedirect");
    if (redctUrl != null) 
      // リダイレクトURLが設定されていれば追跡
      window.location.href = redctUrl;

世捨て人世捨て人 2017/09/05 22:22 「しかし、この方法は「"Content-Type"ヘッダが"text/html"である正常なレスポンス」があったら使えません。」??何故!?
サーバーがtext/htmlを返してきたのだから、そのままページを表示すればいいのでは!?

2008-05-13

XMLHttpRequestオブジェクトでRedirectをハンドリングするには?(リダイレクトを拾う方法)

| 21:45

XMLHttpRequestオブジェクトから送信したリクエストに対し、サーバリダイレクト応答(ステータスコード=302)を返したときのハンドリングってどうやればいいんだろうか?と悩んだのでその記録。

解決したかったのは、以下のような問題。

  1. XMLHttpRequestで送ったリクエストが、サーバで認証エラー(セッションタイムアウトなど)となる
  2. このときサーバは認証エラー(=401)を返すのではなく、ログインページへのリダイレクトを返す
  3. クライアントXMLHttpRequest)は、リダイレクト応答をうけとり、自動的にリダイレクト先を追跡する
  4. 結果、クライアントログインページのHTMLを取得する(このときステータスコード=200)
  5. しかし、そもそもクライアントJSON形式のデータを期待しているためスクリプトエラーとなる

調べてみたところ、XMLHttpRequestリダイレクト応答をうけとると何事もなかったかのようにリダイレクト先にリクエストを送信してしまうようだ。そのため、クライアント側ではリダイレクトされたかどうかが判別できない(ステータスコードは常に200)。これでは困るのでステータスコード以外について調べてみたところ、レスポンスヘッダーの取得はできるようだ。これは都合がいい。

というのは、今回問題が発生したWebアプリではXMLHttpRequestのレスポンスは『必ず』JSON形式(=text/plain)としている。なので、text/htmlのレスポンスが返されたら、それはリダイレクトとみなすことができる。

完全な解決策とはいえないけど、以下のコードで問題解決。

httpRequest.onreadystatechange = function() {
  if (httpRequest.readyState == 4 && httpRequest.status == 200) {
    var cType = httpRequest.getResponseHeader("Content-Type");
    if (cType.toLowerCase().indexOf("text/plain") == -1) 
      window.location.href = url;                                             ← ここで認証エラーとなったリクエストを再送→リダイレクト
    // 以下、省略