我有一个从网站获取html的任务,在我转到该页面之前我需要登录。
我使用的是低级别的api url fetch服务。这是我的代码测试代码:
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引擎上部署并测试它时,我收到响应代码500并出现以下错误:
viewstate MAC验证失败。如果此应用程序由Web场或群集托管,请确保&gt;该配置指定相同的validationKey和验证算法。 &gt;无法在群集中使用AutoGenerate。
描述:执行当前Web请求期间发生了未处理的异常。请>查看堆栈跟踪,以获取有关错误及其在代码中的起源位置的更多信息。
异常详细信息:System.Web.HttpException:viewstate MAC验证失败。如果此应用程序&gt;由Web场或群集托管,请确保配置指定相同的&gt; validationKey和验证算法。无法在群集中使用AutoGenerate。
似乎ASP方面出现了一些错误。
我的代码是否有问题或应用引擎有些限制?
答案 0 :(得分:1)
看起来你正在对一个aspx页面进行POST
。
当aspx页面收到POST
请求时,它会期望一些隐藏的输入存在编码的ViewState - 如果您浏览到相关页面并且“查看源代码”,您应该会在{{{ 1}}标签看起来像这样:
<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" />
请求没有存在这些值,所以它在解码和验证它们时遇到了问题(这个错误意味着什么 - 在其他情况下它也可能因其他原因而出现)。
有几种可能的解决方案:
1 - 如果您有权访问该站点的代码,并且登录页面不需要ViewState,您可以尝试在POST
指令中的页面级别将其关闭:
@Page
2 - 你可以做一个双重请求
- 在登录页面上执行<%@ Page ViewStateMode="Disabled" .... %>
请求,以检索任何缺少的隐藏字段的值
- 使用这些值并将其包含在GET
修改的 是的,从你的评论中我可以看到你已经包含了隐藏的表格字段 - 道歉!
在这种情况下,另一种可能性是登录页面处于负载平衡环境中。该环境中的每个服务器将具有不同的POST
值(用于对ViewState进行编码/解码)。您可能正在阅读一个并发布到另一个。一些LB将ArrowPoint cookie注入响应,以确保您在请求之间“坚持”到同一服务器。
我可以看到你已经在MachineKey
中添加了一个Cookie,但我无法看到它的定义位置。是来自第一个POST
请求,还是自定义Cookie?如果您还没有尝试过,可以尝试使用原始GET
中的cookie来检索登录页面HTML吗?除此之外,我没有想法 - 抱歉!
答案 1 :(得分:0)
很常见,当您尝试在asp.net上模拟postBack时,需要进行POST:
login
,password
)__VIEWSTATE
,__VIEWSTATEENCRYPTED
(即使它是空的!),__EVENTVALIDATION
__EVENTTARGET
和__EVENTARGUMENT