我有一个从网站获取html的任务,在转到该页面之前,我需要登录。
我使用了底层API网址提取服务。这是我的代码测试代码:
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";
它可以在我的开发机上正常工作,但是当我在应用程序引擎上部署并对其进行测试时,我得到响应代码500和以下错误:
验证视图状态MAC失败。如果此应用程序由Web场或群集托管,请确保该配置指定相同的validationKey和验证算法。> AutoGenerate不能在集群中使用。 说明:执行当前Web请求期间发生未处理的异常。请>检查堆栈跟踪,以获取有关错误及其在代码中起源的更多信息。 异常详细信息:System.Web.HttpException:验证视图状态MAC失败。如果此应用程序由Web场或群集托管,请确保配置指定相同的> validationKey和验证算法。自动生成不能在群集中使用。
验证视图状态MAC失败。如果此应用程序由Web场或群集托管,请确保该配置指定相同的validationKey和验证算法。> AutoGenerate不能在集群中使用。
说明:执行当前Web请求期间发生未处理的异常。请>检查堆栈跟踪,以获取有关错误及其在代码中起源的更多信息。
异常详细信息:System.Web.HttpException:验证视图状态MAC失败。如果此应用程序由Web场或群集托管,请确保配置指定相同的> validationKey和验证算法。自动生成不能在群集中使用。
似乎在ASP端发生了一些错误。
我的代码有什么问题或对App Engine的限制吗?
看来您正在POST对aspx页面执行操作。
POST
当aspx页面接收到POST请求时,它会期望一些隐藏的输入,这些隐藏的输入具有已编码的ViewState- 如果浏览到有问题的页面和“查看源代码”,则应该在<form />标记内看到一些类似于以下内容的字段:
<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
<%@ Page ViewStateMode="Disabled" .... %>
2-您可以执行双重请求- GET在登录页面上进行请求以检索所有缺少的隐藏字段的值-使用这些值并将其包括在您的POST
GET
编辑 啊,是的,从您的评论中我可以看到您已经包含了隐藏的表单字段-抱歉!
在这种情况下,另一种可能性是登录页面处于负载平衡的环境中。该环境中的每个服务器将具有一个不同的MachineKey值(用于对ViewState进行编码/解码)。您可能正在阅读中的一个,然后在另一个中发布。一些LB将ArrowPoint cookie注入响应中,以确保您在请求之间“粘贴”到同一服务器。
MachineKey
我可以看到您已经在其中包含一个cookie POST,但看不到它的定义位置。是来自第一个GET请求,还是自定义cookie?如果您还没有尝试过,也许尝试使用原始的cookie来GET获取登录页面HTML?除此之外,我没主意- 对不起!