我在Delphi XE中使用DataSnap創建了一個REST Web服務。我使用XMLHttpRequest JavaScript對象調用服務器方法。我在XMLHttpRequest Open方法的第四個和第五個可選參數中傳遞用於驗證的用戶名和密碼。爲什麼OnUserAuthenticate在DataSnap REST服務器上被調用兩次?
當我在Delphi中加載我的DataSnap服務器並將調試器附加到IIS(我正在使用IIS 7.5)時,我可以看到第一次調用其中一個服務器方法導致DSAuthenticationManager的OnUserAuthenticate事件被調用兩次。
在第一次調用的OnUserAuthenticate事件處理程序的用戶和密碼參數爲空字符串。在第二次調用中,我在XMLHttpRequest Open方法中傳遞的用戶名和密碼出現在這些參數中。
用戶通過身份驗證後,使用XMLHttpRequest對任何服務器方法的任何後續調用都會導致對OnUserAuthenticate事件處理程序的單個調用,並分別在用戶和密碼參數中顯示用戶的用戶名和密碼。
我已經考察了許多了DataSnap類的源代碼,並沒有發現代碼,會導致這樣的效果,這是導致我認爲這種行爲可能會在瀏覽器或IIS起源。
爲什麼OnUserAuthenticate被在第一服務器的方法調用調用了兩次,什麼是生產這種效果呢?
針對墊德隆的回答,我顯示我在用的打電話給我的服務器方法的通用功能之一。這種特殊的方法進行同步呼叫。 baseURL參數通常是一個類似於http://mydomain.com/myservice/myservice.dll/datasnap/rest/tservermethods1的字符串,方法可能是myserver方法。附加參數用於將參數傳遞給服務器的方法:
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);
}
編輯:萊克斯李似乎是正確的,即IIS僅使用基本認證如果失敗的第一請求。另外,Mat是正確的,OnUserAuthenticate應該只在每個會話中調用一次。在檢查了他提供的鏈接後,很明顯我沒有捕獲並返回會話ID。這是一個可以工作的代碼示例,這次是非同步的。它捕獲sessionid並將其存儲在隱藏字段中。然後它將會話標識返回到Pragma標題中的每個後續調用中。
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);
}
編輯:當我先貼這兩個代碼示例我包括在開放的XMLHttpRequest方法的第四和第五參數樣本用戶名和密碼。我在測試過程中明確地傳遞了這些值。不推薦傳遞這樣的參數,所以我在這個編輯中刪除了這些參數。如果您省略了這些密碼,並且不使用其他方法(例如在您的第一個REST服務器方法調用的標頭中)傳遞它們,則瀏覽器將顯示一個對話框,詢問用戶這些信息。一旦提供了用戶名和密碼,瀏覽器將在會話的其餘部分記住這些信息。如果您關閉然後重新打開瀏覽器並調用另一個REST服務器方法,您將再次受到用戶名和密碼的挑戰。當然,這假設您通過OnUserAuthenticate事件處理程序拒絕無效用戶。
這看起來是正確的。我使用wireshark檢查了數據包。第一個請求不包含基本認證頭信息,而第二個請求包含。謝謝! –