3

我的任务是从网站获取 html,在我进入需要登录的页面之前。

我使用低级 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";

它在我的开发机器上运行良好,但是当我在应用引擎上部署并测试它时,我得到响应代码 500 和以下错误:

视图状态 MAC 验证失败。如果此应用程序由 Web Farm 或集群托管,请确保 > 该配置指定相同的验证密钥和验证算法。>AutoGenerate 不能在集群中使用。

说明:执行当前 Web 请求期间发生未处理的异常。请>查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

异常详细信息:System.Web.HttpException:视图状态 MAC 验证失败。如果此应用程序 > 由 Web Farm 或集群托管,请确保配置指定相同的 >validationKey 和验证算法。AutoGenerate 不能在集群中使用。

似乎在 ASP 端发生了一些错误。

我的代码有问题还是应用引擎有一些限制?

4

2 回答 2

2

看起来你正在做一个POSTaspx 页面。

当一个 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 注入到响应中,以确保您在请求之间“坚持”到同一台服务器。

我可以看到你已经在你的 cookie 中包含了一个 cookie POST,但我看不到它是在哪里定义的。是来自第一个GET请求,还是自定义 cookie?如果您还没有尝试过,也许可以尝试使用GET您正在检索登录页面 HTML 的原始 cookie?除此之外,我没有想法 - 对不起!

于 2012-09-07T13:58:58.290 回答
0

通常,当您尝试在 asp.net 上模拟 postBack 时,您需要 POST:

  • 从第一个请求 cookie 中保留以作用于同一会话
  • 数据字段 ( login, password)
  • 从第一页隐藏的:__VIEWSTATE__VIEWSTATEENCRYPTED(即使它是空的!),__EVENTVALIDATION
  • 如果您发送一些操作项,也许您还需要包含隐藏字段__EVENTTARGET__EVENTARGUMENT
于 2019-12-08T05:49:34.403 回答