为什么我的Http客户端在指定凭据时发出2个请求?

我创建了RESTful webservice(WCF),我检查每个请求的凭据。 我的一个客户是Android应用程序,服务器端的一切似乎都很棒。 我收到请求,如果它有正确的标题 – 我处理它等。

现在我创建了使用此服务的客户端应用程序。 这是我做GET的方式:

// Create the web request var request = WebRequest.Create(Context.ServiceURL + uri) as HttpWebRequest; if (request != null) { request.ContentType = "application/json"; // Add authentication to request request.Credentials = new NetworkCredential(Context.UserName, Context.Password); // Get response using (var response = request.GetResponse() as HttpWebResponse) { // Get the response stream if (response != null) { var reader = new StreamReader(response.GetResponseStream()); // Console application output var s = reader.ReadToEnd(); var serializer = new JavaScriptSerializer(); var returnValue = (T)serializer.Deserialize(s, typeof(T)); return returnValue; } } } 

所以,这段代码得到了我的资源并反序列化它。 如你所见 – 我在通话中传递凭据。

然后,当在服务器端进行调试时,我注意到每次都有2个请求 – 一个没有认证头,然后服务器发回响应,第二个请求带有凭证。 我认为这对我的服务器有害 – 我宁愿不做任何往返。 我应该如何更改客户端,以免发生? 查看Fiddler的截图

第一个BAD请求

第二个GOOD请求

编辑

这是我在Android中使用的JAVA代码 – 它不会进行双重调用:

 MyHttpResponse response = new MyHttpResponse(); HttpClient client = mMyApplication.getHttpClient(); try { HttpGet request = new HttpGet(serviceURL + url); request.setHeader(new BasicHeader(HTTP.CONTENT_TYPE, "application/json")); request.addHeader("Authorization", "Basic " + Preferences.getAuthorizationTicket(mContext)); ResponseHandler handler = new BasicResponseHandler(); response.Body = client.execute(request, handler); response.Code = HttpURLConnection.HTTP_OK; response.Message = "OK"; } catch (HttpResponseException e) { response.Code = e.getStatusCode(); response.Message = e.getMessage(); LogData.InsertError(mContext, e); } 

初始请求不会指定用于身份validation的基本标头。 此外,由于指定了领域,您必须从服务器获取该领域。 所以你必须问一次:“嘿,我需要这些东西”,服务器就是“你是谁?回答的领域是’安全区’。” (因为领域在这里意味着什么)只是因为你在这里添加了它:

 request.Credentials = new NetworkCredential(Context.UserName, Context.Password); 

并不意味着它确实会在每次请求时附加。

然后你用用户名/密码回复(在这种情况下你正在做BASIC,所以它的base64编码为name:password)服务器解码它并说“好吧,你们都清楚,这是你的数据”。

这将定期发生,你可以做很多事情。 我建议你也打开HTTPS,因为身份validation是通过互联网以纯文本forms进行的。 (实际上你所展示的内容似乎是通过内联网,但如果你确实通过互联网进行了https)。

以下是维基百科的链接,可能会对您有所帮助: http : //en.wikipedia.org/wiki/Basic_access_authentication

好,我知道了。 我手动设置HttpHeader而不是使用request.Credentials

 request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(Context.UserName + ":" + Context.Password))); 

现在我只看到了预期的单个请求..

作为选项,您可以使用HttpClientHandler的PreAuthenticate属性 。 这将需要更多的几行

  var client = new HttpClient(new HttpClientHandler { Credentials = yourCredentials, PreAuthenticate = true }); 

使用此方法时,只有第一个请求在没有凭据的情况下发送,但所有其他请求都可以。