2012-09-07 19 views
3

我有一個任務可以從網站獲取HTML,之前我去那個頁面,我需要登錄視圖狀態MAC的驗證失敗。得到通過URL從谷歌應用程序引擎發送POST請求時,提取服務

我用一個低級別的api url抓取服務。這裏是我的代碼測試代碼:

private String postPage(String loginPageHtml) throws IOException{ 
    String charset = "UTF-8"; 
    Document doc = Jsoup.parse(loginPageHtml); 
    Iterator<Element> inputHiddensIter = doc.select("form").first().select("input[type=hidden]").iterator(); 

    String paramStr = ""; 

    paramStr += "Username" + "=" + URLEncoder.encode("username", charset) + "&"; 
    paramStr += "Password" + "=" + URLEncoder.encode("password", charset) + "&"; 
    paramStr += "ImageButton1.x" + "=" + URLEncoder.encode("50", charset) + "&"; 
    paramStr += "ImageButton1.y" + "=" + URLEncoder.encode("10", charset) + "&"; 

    while (inputHiddensIter.hasNext()) { 
     Element ele = inputHiddensIter.next(); 
     String name = ele.attr("name"); 
     String val = ele.attr("value"); 
     paramStr += name + "=" + URLEncoder.encode(val, charset) + "&"; 
    } 

    URL urlObj = new URL(LOG_IN_PAGE); 
    URLFetchService fetcher = URLFetchServiceFactory.getURLFetchService(); 
    HTTPRequest request = new HTTPRequest(urlObj, HTTPMethod.POST); 
    HTTPHeader header = new HTTPHeader("Content-Type", "application/x-www-form-urlencoded"); 
    HTTPHeader header3 = new HTTPHeader("Content-Language", "en-US"); 
    HTTPHeader header4 = new HTTPHeader("User-Agent", DEFAULT_USER_AGENT); 
    if(!cookie.isEmpty()){ 
     request.addHeader(new HTTPHeader("Set-Cookie", cookie)); 
    } 
    request.addHeader(header); 
    request.addHeader(header3); 
    request.addHeader(header4); 
    request.setPayload(paramStr.getBytes()); 
    request.getFetchOptions().setDeadline(30d); 
    HTTPResponse response = null; 

    try{ 
     response = fetcher.fetch(request); 
     byte[] content = response.getContent(); 

     int responseCode = response.getResponseCode(); 
     log.severe("Response Code : " + responseCode); 
     List<HTTPHeader>headers = response.getHeaders(); 

     for(HTTPHeader h : headers) { 
      String headerName = h.getName(); 
      if(headerName.equals("Set-Cookie")){ 
       cookie = h.getValue(); 
      } 
     } 

     String s = new String(content, "UTF-8"); 

     return s; 
    }catch (IOException e){ 
     /* ... */ 
    } 

    return ""; 
} 

這是我的默認的用戶代理:

private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.83 Safari/537.1"; 

它工作正常,我的開發機器上,但是當我部署在App Engine上測試它,我得到響應代碼500和以下錯誤:

Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure >that configuration specifies the same validationKey and validation algorithm. >AutoGenerate cannot be used in a cluster.

Description: An unhandled exception occurred during the execution of the current web request. Please >review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Web.HttpException: Validation of viewstate MAC failed. If this application >is hosted by a Web Farm or cluster, ensure that configuration specifies the same >validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.

ASP似乎出現了一些錯誤。

我的代碼有問題或者應用程序引擎有一些限制嗎?

+0

我也有這個確切的問題,除了我使用HttpUrlConnection而不是URLFetchService。當我在我的開發機器上執行該帖子時,它工作得很好,但在Google App Engine上部署時不起作用。你有沒有設法解決這個問題? – CrashproofCode

回答

1

看起來您正在爲一個aspx頁面做一個POST

當一個aspx頁面收到POST請求,它預計它有一個編碼ViewState中存在一些隱藏的輸入 - 如果你瀏覽到頁面中的問題,「查看源文件」,你應該看到剛剛<form />標籤裏面的一些字段看起來像這樣:

<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" /> 
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" /> 
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="xxxxxxxxx" /> 

由於您提交沒有這些值目前,它有麻煩解碼和驗證他們POST請求(這是什麼錯誤意味着 - 它也可以突然出現在其他情況下其他原因)。

有幾個可能的解決方案是:

1 - 如果你有機會獲得該網站的代碼,登錄頁面不需要ViewState的,你可以嘗試在頁面關閉它在@Page指令中級別:

<%@ Page ViewStateMode="Disabled" .... %> 

2 - 你可以做一個雙重要求 - 做登錄頁面上GET請求來檢索值,任何遺失隱藏字段 - 使用這些值,並將其納入你的POST

編輯 啊是的,從您的評論我可以看到,你已經包括隱藏的表單域 - 道歉!

在這種情況下,另一種可能性是登錄頁面處於負載平衡環境。該環境中的每臺服務器將具有不同的MachineKey值(用於對ViewState進行編碼/解碼)。您可能正在閱讀並張貼到其他人。一些LB將ArrowPoint cookie注入到響應中,以確保您在請求之間「粘」到相同的服務器。

我可以看到你已經在你的POST中包含一個cookie,但是我看不到它的定義。它是從第一個GET請求,還是它的自定義cookie?如果您尚未嘗試過,可嘗試使用您檢索登錄頁面HTML的原始GET中的cookie?除此之外,我沒有想法 - 對不起!

+0

感謝您的回答,但對於您的第一點,我沒有訪問asp端。我已經嘗試獲取隱藏窗體(__VIEW和__EVENT)值,並將它們包含在發佈請求中,就像您在while循環中看到的一樣。但它不起作用。 –

+0

啊是的 - 已經給答案增加了一個額外的建議 - 你可能已經完成了。 – tristankoffee

+0

我從第一個獲取請求到登錄頁面獲取一個cookie,無論如何感謝您的建議。 –

相關問題