2012-01-09 100 views
2

我正在嘗試使用我在使用HttpClient 4.0.3的回覆帖子的方法中收到的Cookie;HttpClient 4.x如何使用cookies?

這裏是我的代碼:

public void generateRequest() 
{ 
    DefaultHttpClient httpclient = new DefaultHttpClient(); 
    HttpPost httppost = new HttpPost("http://mysite.com/login"); 
    httpclient.getParams().setParameter("http.useragent", "Custom Browser"); 
    httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, 
      HttpVersion.HTTP_1_1); 
    httpclient.getParams().setParameter(ClientPNames.COOKIE_POLICY, 
      CookiePolicy.BROWSER_COMPATIBILITY); 

    CookieStore cookieStore = new BasicCookieStore(); 
    HttpContext localContext = new BasicHttpContext(); 
    localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); 

    try 
    { 
     LOG.info("Status Code: sending"); 
     List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); 
     nameValuePairs.add(new BasicNameValuePair("email", "john%40gmail.com")); 
     nameValuePairs.add(new BasicNameValuePair("password", "mypassword")); 
     httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); 
     httppost.setHeader("ContentType", "application/x-www-form-urlencoded"); 
     HttpResponse response = httpclient.execute(httppost, localContext); 
     HttpEntity entity = response.getEntity(); 
     if (entity != null) 
     { 
      entity.consumeContent(); 
     } 
     iterateCookies(httpclient); 

    } 
    catch (ClientProtocolException e) 
    { 
     LOG.error("ClientProtocolException", e); 
    } 
    catch (IOException e) 
    { 
     LOG.error("IOException", e); 
    } 
} 

private void iterateCookies(DefaultHttpClient httpclient) 
{ 
    List<Cookie> cookies = httpclient.getCookieStore().getCookies(); 
    if (cookies.isEmpty()) 
    { 
     System.out.println("No cookies"); 
    } 
    else 
    { 
     for (Cookie c : cookies) 
     { 
      System.out.println("-" + c.toString()); 
     } 
    } 
} 

但我不斷收到No cookies註銷,即使當我使用web-sniffer.net,我得到這樣的迴應:

Status:   HTTP/1.1 302 Found 
Cache-Control:  private, no-store  
Content-Type:  text/html; charset=utf-8 
Location:   http://www.mysite.com/loginok.html 
Server:   Microsoft-IIS/7.0  
X-AspNet-Version: 2.0.50727  
Set-Cookie:  USER=DDA5FF4E1C30661EC61CFA; domain=.mysite.com; expires=Tue, 08-Jan-2013  18:39:53 GMT; path=/ 
Set-Cookie:  LOGIN=D6CC13A23DCF56AF81CFAF; domain=.mysite.com; path=/ Date: Mon, 09  Jan 2012 18:39:53 GMT 
Connection:  close  
Content-Length: 165 

所有的例子我在網上發現,任何類型的意義都可以參考HttpClient 3.x,您可以將CookiePolicy設置爲IGNORE,並手動處理Set-Cookie標題。我不明白爲什麼在4.x這很困難。由於多種原因,我需要訪問USER散列。任何人都可以告訴我如何在地獄我可以訪問它?

UPDATE

我發現以下C#代碼做同樣的事情,並正常工作。

private static string TryGetCookie(string user, string pass, string baseurl) 
    { 
     string body = string.Format("email={0}&password={1}", user, pass); 
     byte[] bodyData = StringUtils.StringToASCIIBytes(body); 

     HttpWebRequest req = WebRequest.Create(baseurl) as HttpWebRequest; 

     if (null != req.Proxy) 
     { 
      req.Proxy.Credentials = CredentialCache.DefaultCredentials; 
     } 

     req.AllowAutoRedirect = false; 
     req.Method = "Post"; 
     req.ContentType = "application/x-www-form-urlencoded"; 
     req.ContentLength = bodyData.Length; 

     using (Stream reqBody = req.GetRequestStream()) 
     { 
      reqBody.Write(bodyData, 0, bodyData.Length); 
      reqBody.Close(); 
     } 

     HttpWebResponse resp1 = req.GetResponse() as HttpWebResponse; 

     string cookie = resp1.Headers["Set-Cookie"]; 

     if(string.IsNullOrEmpty(cookie)) 
     { 
      if (0 < resp1.ContentLength) 
      { 
       // it's probably not an event day, and the server is returning a singlecharacter 
       StreamReader stringReader = new StreamReader(resp1.GetResponseStream()); 

       return stringReader.ReadToEnd(); 
      } 

      return null; 
     } 

     return ParseCookie(cookie); 
    } 

我相信我的Java代碼是不正確形成POST請求,因爲當我使用一個URLConnection並打印請求頭從web-sniffer.net如下:

POST /reg/login HTTP/1.1[CRLF] 
Host: live-timing.formula1.com[CRLF] 
Connection: close[CRLF] 
User-Agent: Web-sniffer/1.0.37 (+http://web-sniffer.net/)[CRLF] 
Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7[CRLF] 
Cache-Control: no-cache[CRLF] 
Accept-Language: de,en;q=0.7,en-us;q=0.3[CRLF] 
Referer: http://web-sniffer.net/[CRLF] 
Content-type: application/x-www-form-urlencoded[CRLF] 
Content-length: 53[CRLF] 
[CRLF] 
email=john%40gmail.com&password=mypassword 

我得到的迴應包含set-cookies標頭的服務器。我的java代碼是否生成與web-sniffer.net相同的請求?

我看到使用此代碼生成的交方法:

PostMethod authPost = new PostMethod("http://localhost:8000/webTest/j_security_check"); 
// authPost.setFollowRedirects(false); 
NameValuePair[] data = { 
new NameValuePair("email", "john%40gmail.com"), 
new NameValuePair("password", "mypassword") 
}; 
authPost.setRequestBody(data); 
status = client.executeMethod(authPost); 

這裏的主要區別在於,NameValuePair數據在請求體設置,而不是設置爲實體。這是否有所作爲?這會產生正確的請求標題嗎?

回答

0

這總是一個簡單的答案!調試完C#後,我發現了另一個C程序。我正在跳槍,並在電子郵件地址上做我自己的編碼,以刪除@角色。這是問題!無論它是否存在,其他任何東西似乎都沒有什麼區別!現在,該代碼看起來像:

public void postData(final String email, final String password) 
{ 
    DefaultHttpClient client = new DefaultHttpClient(); 
    HttpPost post = new HttpPost(LOGIN_URL); 
    client.getParams().setParameter("http.useragent", "Custom Browser"); 
    client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); 

    try 
    { 
     List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); 
     nameValuePairs.add(new BasicNameValuePair("email", email)); 
     nameValuePairs.add(new BasicNameValuePair("password", password)); 
     UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8); 
     entity.setContentType("application/x-www-form-urlencoded"); 
     post.setEntity(entity); 

     printHeaders(client.execute(post)); 
     printCookies(client.getCookieStore()); 
    } 
    catch (ClientProtocolException e) 
    { 
     LOG.error("ClientProtocolException", e); 
    } 
    catch (IOException e) 
    { 
     LOG.error("IOException", e); 
    } 
} 

和輸出現在看起來像:

Response Headers: 
-Cache-Control: private, no-store 
-Content-Type: text/html; charset=utf-8 
-Server: Microsoft-IIS/7.0 
-X-AspNet-Version: 2.0.50727 
-Set-Cookie: USER=3D907C0EB817FD7...92F79616E6E96026E24; domain=.mysite.com; expires=Thu, 10-Jan-2013 20:22:16 GMT; path=/ 
-Set-Cookie: LOGIN=7B7028DC2DA82...5CA6FB6CD6C2B1; domain=.mysite.com; path=/ 
-Date: Wed, 11 Jan 2012 20:22:16 GMT 
-Content-Length: 165 
-Cookie:: [version: 0][name: USER][value: 3D907C0E...E26E24][domain: .mysite.com][path: /][expiry: Thu Jan 10 20:22:16 GMT 2013] 
-Cookie:: [version: 0][name: LOGIN][value: 7B7028D...D6C2B1][domain: .mysite.com][path: /][expiry: null] 
0

我認爲問題在於你在這裏混合了兩種「風格」:一方面你創建自己的BasicCookieStore並將其放入你的HttpContext;另一方面,當打印餅乾時,您循環訪問DefaultHttpClient中的餅乾店。

因此,要麼改變iterateCookies使用本地cookie存儲,或只使用由DefaultHttpClient提供的一個。正如您在DefaultHttpClientjavadoc中看到的那樣,它應該自動將響應cookie添加到其內部cookie存儲。

+0

謝謝你的幫助。然而,在迭代cookie中使用'BasicCookieStore'不會返回cookie,就像使用DefaultHttpClient的內部cookie存儲一樣。我不知道爲什麼... – 2012-01-09 22:29:31

+0

奇怪。幾天前我在一個項目中使用了HttpClient(版本4.1.2)。我的代碼和你的代碼很相似 - 外部的BasicCookieStore - 但是當我遍歷它時,cookies就在那裏。 – waxwing 2012-01-09 22:39:21

+0

嗯...可能是一個4.0.3的錯誤?我無法想象,但它是一個非常巨大的陷阱。是否還有其他系統變量需要設置?我看到他們在一些文檔中提到過幾次。 – 2012-01-09 23:07:23

3

這兩個餅乾看起來都很可疑。兩者都使用過時的Netscape cookie草稿格式。兩者都具有無效的域屬性值。 LOGIN出現格式錯誤(路徑屬性後缺少分號)。所以,很可能這兩個cookie都被HttpClient拒絕了。

你可以找出是否這是通過運行的HttpClient這裏描述的上下文日誌接通的情況下: http://hc.apache.org/httpcomponents-client-ga/logging.html

一個最後一句話。通常,在使用HttpClient 4.x時,不應該干涉cookie策略。默認的BEST_MATCH政策會根據Set-Cookie標題值的組成自動將Cookie處理委託給特定的Cookie規範實施。爲了完全禁用cookie處理,應該從協議處理鏈中刪除cookie處理協議攔截器。

希望這會有所幫助。

+0

感謝您的洞察力。一旦我訪問我的開發機器,我會立即刪除cookie策略。關於我編輯上面的原始帖子,如果我沒有設置Content-type:application/x-www-form-urlencoded Content-length:53'屬性,我似乎沒有得到任何cookie。然而,當我嘗試使用HttpClient設置Content-Length時,我在響應頭部收到一個異常,說ContentLength屬性已經設置。任何想法,如果這可能會導致錯誤,如果是的話,如何解決它? – 2012-01-11 15:08:54

+1

@克里斯羅賓遜:不要插手內容長度的價值!誤判它很容易。讓HttpClient完成它的工作並根據請求消息中包含的內容實體的長度自動計算值 – oleg 2012-01-11 15:43:25

+1

@Chris Robinson:HttpClient是一個行爲良好的HttpClient,它還將charset屬性添加到Content-Type標頭值。顯然,Web應用程序太笨了,無法正確解析Content-Type標題值。使用StringEntity#setCotnentType()方法來覆蓋默認值,並將其設置爲「應用程序/ x-WWW的形式了urlencoded」(沒有charset屬性) – oleg 2012-01-11 15:45:36