3

Delphi XE で DataSnap を使用して REST Web サービスを作成しました。XMLHttpRequest JavaScript オブジェクトを使用してサーバー メソッドを呼び出しています。XMLHttpRequest Open メソッドの 4 番目と 5 番目のオプション パラメータで、認証用のユーザー名とパスワードを渡しています。

DataSnap サーバーを Delphi にロードし、デバッガーを IIS にアタッチすると (IIS 7.5 を使用しています)、サーバー メソッドの 1 つを初めて呼び出すと、DSAuthenticationManager の OnUserAuthenticate イベントが 2 回呼び出されることがわかります。

最初の呼び出しでは、OnUserAuthenticate イベント ハンドラーのユーザーとパスワードのパラメーターは空の文字列です。2 回目の呼び出しでは、XMLHttpRequest Open メソッドで渡したユーザー名とパスワードがこれらのパラメーターに表示されます。

ユーザーが認証されると、その後 XMLHttpRequest を使用していずれかのサーバー メソッドを呼び出すと、OnUserAuthenticate イベント ハンドラーが 1 回呼び出され、ユーザーのユーザー名とパスワードがそれぞれ user パラメーターと password パラメーターに表示されます。

多くの DataSnap クラスのソース コードを調べましたが、この影響を引き起こすコードは見つかりませんでした。このため、この動作はブラウザまたは IIS に起因するのではないかと考えています。

最初のサーバー メソッド呼び出しで OnUserAuthenticate が 2 回呼び出されるのはなぜですか? また、何がこの影響を生み出しているのですか?


Mat DeLong の回答に応えて、サーバー メソッドを呼び出すために使用している汎用関数の 1 つを示しています。この特定のメソッドは、同期呼び出しを行います。通常、baseURL パラメーターはhttp://mydomain.com/myservice/myservice.dll/datasnap/rest/tservermethods1のような文字列で、メソッドは myservermethod の場合があります。追加のパラメーターを使用して、サーバー メソッドにパラメーターを渡します。

function getJSONSync(baseURL, method) {
  var request = new XMLHttpRequest();
  var url = baseURL + method;
  for (var i= 2; i < arguments.length; i++) {
    url += "/" + arguments[i];
  }
  request.open("GET", encodeURI(url), false);
  request.send(null);
  if (request.status != 200) {
    throw new Error(request.statusText);
  } 
  return jQuery.parseJSON(request.responseText);
}

編集: Lex Li は正しいようです。IIS は、最初の要求で失敗した場合にのみ基本認証を使用します。また、OnUserAuthenticate はセッションごとに 1 回だけ呼び出す必要があるという Mat の指摘は正しいです。彼が提供したリンクを調べたところ、セッション ID を取得して返すことに失敗していたことが明らかになりました。今回は非同期で動作するコードの例を次に示します。sessionid をキャプチャし、隠しフィールドに格納します。その後、Pragma ヘッダー内の後続の各呼び出しでそのセッション ID を返します。

function getJSONAsync(callback, baseURL, method) {
  var request = new XMLHttpRequest();
  var timedout = false;
  request.onreadystatechange = function() {
     if (request.readyState !== 4) { return }
    if (timedout) { return }
    if (request.status >= 200 && request.status < 300)
    {
      callback(jQuery.parseJSON(request.responseText));
      //store the sessionid in a hidden field
      $("#sessionid").val(request.getResponseHeader('Pragma').split(',')[0].split("=")[1]);
    }
  }
  var url = baseURL + method;
  for (var i= 3; i < arguments.length; i++) {
    url += "/" + arguments[i];
  }
  request.open("GET", encodeURI(url), true);
  //pass the sessionid in the Pragma header, if available
  if (! $("#sessionid").val() == "") {
    request.setRequestHeader("Pragma", "dssession="+$("#sessionid").val());
  }
  //time out if request does not complete in 10 seconds
  var timer = setTimeout(function() { timedout = true; request.abort(); }, 10000);
  request.send(null);
}

編集: これら 2 つのコード サンプルを最初に投稿したとき、サンプルのユーザー名とパスワードを XMLHttpRequest オープン メソッドの 4 番目と 5 番目のパラメーターに含めました。テスト中にこれらの値を明示的に渡していました。このようなパラメーターを渡すことはお勧めできないため、この編集でこれらのパラメーターを削除しました。これらのパスワードを省略し、別のメソッド (最初の REST サーバー メソッド呼び出しのヘッダーなど) を使用してパスワードを渡さない場合、ブラウザーはユーザーにこの情報を求めるダイアログ ボックスを表示します。ユーザー名とパスワードが提供されると、ブラウザーはセッションの残りの間、この情報を記憶します。ブラウザーを閉じてから再度開き、別の REST サーバー メソッドを呼び出すと、ユーザー名とパスワードの入力を再度求められます。もちろん、これは、

4

2 に答える 2

3

これは、ASP.NET などの他のテクノロジに対する IIS の一般的な動作です。

最初のリクエストにはユーザー資格情報が含まれていないため、401 レスポンスがトリガーされます。次に、2 番目の要求でユーザー資格情報が送信され、IIS は 200 を返すことができます。

これが DataSnap に当てはまるかどうかはわかりませんが、ネットワーク パケットをキャプチャすればわかるかもしれません。

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.preauthenticate.aspx

于 2011-08-06T12:20:46.570 に答える