3

そのページに移動する前に、ログインする必要があるWebサイトからhtmlをフェッチするタスクがあります。

低レベルのAPIURLフェッチサービスを使用しています。これが私のコードテストコードです:

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と次のエラーが発生します。

ビューステートMACの検証に失敗しました。このアプリケーションがWebファームまたはクラスターによってホストされている場合は、構成で同じvalidationKeyと検証アルゴリズムが指定されていることを確認してください。>AutoGenerateはクラスターでは使用できません。

説明:現在のWebリクエストの実行中に未処理の例外が発生しました。>エラーとそれがコードのどこで発生したかについての詳細は、スタックトレースを確認してください。

例外の詳細:System.Web.HttpException:ビューステートMACの検証に失敗しました。このアプリケーションがWebファームまたはクラスターによってホストされている場合は、構成で同じ検証キーと検証アルゴリズムが指定されていることを確認してください。AutoGenerateはクラスターでは使用できません。

ASP側でエラーが発生しているようです。

私のコードに何か問題がありますか、またはアプリエンジンにいくつかの制限がありますか?

4

2 に答える 2

2

POSTaspxページに対して 実行しているようです。

aspxページがPOSTリクエストを受信すると、エンコードされたViewStateが存在するいくつかの非表示の入力が必要です。問題のページと「ViewSource」を参照すると、<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は、要求間で同じサーバーに「固執」することを保証するために、応答にArrowPointCookieを挿入します。

すでにCookieが含まれていることはわかりますが、CookieがPOSTどこで定義されているかはわかりません。それは最初のGETリクエストからのものですか、それともカスタムCookieですか?まだ試したことがない場合はGET、ログインページのHTMLを取得している元のCookieを使用してみてください。それ以外は、私はアイデアがありません-ごめんなさい!

于 2012-09-07T13:58:58.290 に答える
0

通常、asp.netでpostBackをエミュレートしようとしている場合は、次のようにPOSTする必要があります。

  • 同じセッションで動作する最初のリクエストCookieから保持されます
  • データフィールド(loginpassword
  • 最初のページから隠されたもの: __VIEWSTATE__VIEWSTATEENCRYPTED(空であっても!)、__EVENTVALIDATION
  • いくつかのアクションアイテムを送信する場合は、非表示のフィールド__EVENTTARGET__EVENTARGUMENT
于 2019-12-08T05:49:34.403 に答える