javascript - 为什么 OnUserAuthenticate 在 DataSnap REST 服务器上被调用两次?

标签 javascript delphi xmlhttprequest delphi-xe datasnap

我在 Delphi XE 中使用 DataSnap 创建了一个 REST Web 服务。我正在使用 XMLHttpRequest JavaScript 对象调用服务器方法。我在 XMLHttpRequest Open 方法的第四个和第五个可选参数中传递用于身份验证的用户名和密码。

当我在 Delphi 中加载我的 DataSnap 服务器并将调试器附加到 IIS(我使用的是 IIS 7.5)时,我可以看到我第一次调用其中一个服务器方法导致 DSAuthenticationManager 的 OnUserAuthenticate 事件被调用两次。

在第一次调用中,OnUserAuthenticate 事件处理程序的用户和密码参数是空字符串。在第二次调用时,我在 XMLHttpRequest Open 方法中传递的用户名和密码出现在这些参数中。

一旦用户通过身份验证,使用 XMLHttpRequest 对任何服务器方法的任何后续调用都会导致对 OnUserAuthenticate 事件处理程序的一次调用,用户的用户名和密码分别出现在用户和密码参数中。

我已经检查了许多 DataSnap 类的源代码,但没有找到会导致这种效果的代码,这使我认为这种行为可能源于浏览器或 IIS。

为什么 OnUserAuthenticate 在第一次服务器方法调用时被调用两次,是什么产生了这种效果?


为了回应 Mat DeLong 的回答,我展示了我用来调用服务器方法的通用函数之一。此特定方法进行同步调用。 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 仅在第一次请求失败时才使用基本身份验证。此外,Mat 是正确的,每个 session 只应调用一次 OnUserAuthenticate。检查他提供的链接后,很明显我未能捕获并返回 session ID。这是一个可以工作的代码示例,这次是异步的。它捕获 sessionid 并将其存储在隐藏字段中。然后,它会在 Pragma header 中的每个后续调用中将该 session 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);
}

编辑:当我第一次发布这两个代码示例时,我在 XMLHttpRequest 打开方法的第四个和第五个参数中包含了示例用户名和密码。我在测试期间明确传递了这些值。不推荐像这样传递参数,所以我在这次编辑中删除了这些参数。如果您省略这些密码,并且不使用其他方法(例如在您的第一个 REST 服务器方法调用的 header 中)传递它们,浏览器将显示一个对话框,要求用户提供此信息。一旦提供了用户名和密码,浏览器将在剩余的 session 中记住此信息。如果您关闭然后重新打开浏览器并调用另一个 REST 服务器方法,您将再次被要求输入用户名和密码。当然,这假定您通过 OnUserAuthenticate 事件处理程序拒绝无效用户。

最佳答案

嗯,这是其他技术(如 ASP.NET)的典型 IIS 行为。

初始请求不包含您的用户凭据,并触发 401 响应。然后第二个请求确实发送了您的用户凭据,然后 IIS 可以返回 200。

不确定这是否适用于 DataSnap,但是如果您捕获网络数据包,您可能会发现它。

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

关于javascript - 为什么 OnUserAuthenticate 在 DataSnap REST 服务器上被调用两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6960469/

相关文章:

javascript - 谷歌云任务不将正文发送到http云函数

delphi - 为什么升级到 Delphi 2007 之后我的加密不起作用?

delphi - 如何恢复或复制组件模板?

javascript - 为什么 CORS 在不同的内容类型下给出不同的响应

javascript - 一遍又一遍地将新的对象值添加到现有的对象值中

javascript - JSX 生成 div 并推送到数组

javascript - Svg transform 属性放置有间隙的元素

string - 当字符串没有自动触发时如何触发 COW

unit-testing - 使用 express 在 node.js 中测试 HTTP 请求

javascript - 快速发送时未​​收到异步 AJAX 请求