8

HttpURLConnection を使用して HTTP POST を実行していますが、常に完全な応答が得られるとは限りません。問題をデバッグしたかったのですが、各行をステップ実行するとうまくいきました。タイミングの問題に違いないと思ったので、Thread.sleep を追加したところ、実際にコードが機能するようになりましたが、これは一時的な回避策にすぎません。なぜこれが起こっているのか、そしてどのように解決するのか疑問に思っています。これが私のコードです:

public static InputStream doPOST(String input, String inputMimeType, String url, Map<String, String> httpHeaders, String expectedMimeType) throws MalformedURLException, IOException {

    URL u = new URL(url);
    URLConnection c = u.openConnection();
    InputStream in = null;
    String mediaType = null;
    if (c instanceof HttpURLConnection) {

        //c.setConnectTimeout(1000000);
        //c.setReadTimeout(1000000);

        HttpURLConnection h = (HttpURLConnection)c;
        h.setRequestMethod("POST");
        //h.setChunkedStreamingMode(-1);
        setAccept(h, expectedMimeType);
        h.setRequestProperty("Content-Type", inputMimeType);

        for(String key: httpHeaders.keySet()) {
            h.setRequestProperty(key, httpHeaders.get(key));

            if (logger.isDebugEnabled()) {
                logger.debug("Request property key : " + key + " / value : " + httpHeaders.get(key));
            }

        }

        h.setDoOutput(true);
        h.connect();

        OutputStream out = h.getOutputStream();

        out.write(input.getBytes());

        out.close();

        mediaType = h.getContentType();

        logger.debug(" ------------------ sleep ------------------ START");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.debug(" ------------------ sleep ------------------ END");

        if (h.getResponseCode() < 400) {
            in = h.getInputStream();
        } else {
            in = h.getErrorStream();
        }
    }
    return in;

}

後で入力ストリームを読み取るために次のことを行います

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while (is.available() > 0) {
            bos.write(is.read());
        }
        is.close();

        //is.read(bytes);
        if (logger.isDebugEnabled()) {
            logger.debug(" Response lenght is : " + is.available());
            //logger.debug("RAW response is " + new String(bytes));
            logger.debug("RAW response is " + new String(bos.toByteArray()));
        }

次の HTTP ヘッダーを生成します。

POST /emailauthentication/ HTTP/1.1
Accept: application/xml
Content-Type: application/xml
Authorization: OAuth oauth_consumer_key="b465472b-d872-42b9-030e-4e74b9b60e39",oauth_nonce="YnDb5eepuLm%2Fbs",oauth_signature="dbN%2FWeWs2G00mk%2BX6uIi3thJxlM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1276524919", oauth_token="", oauth_version="1.0"
User-Agent: Java/1.6.0_20
Host: test:6580
Connection: keep-alive
Content-Length: 1107

他の投稿では、を使用してキープアライブをオフにすることが提案されていました

http.keepAlive=false

システムプロパティ、それを試してみたところ、ヘッダーが次のように変更されました

POST /emailauthentication/ HTTP/1.1
Accept: application/xml
Content-Type: application/xml
Authorization: OAuth oauth_consumer_key="b465472b-d872-42b9-030e-4e74b9b60e39", oauth_nonce="Eaiezrj6X4Ttt0", oauth_signature="ND9fAdZMqbYPR2j%2FXUCZmI90rSI%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1276526608", oauth_token="", oauth_version="1.0"
User-Agent: Java/1.6.0_20
Host: test:6580
Connection: close
Content-Length: 1107

Connection ヘッダーは「close」ですが、まだ応答全体を読み取ることができません。私は何を間違っているのですか?

4

3 に答える 3

14

私はあなたの問題がこの行にあると思います:

while (is.available() > 0) {

javadocによると、availableすべてのデータが利用可能になるまでブロックして待機しないため、最初のパケットを取得するとfalseが返される可能性があります。InputStreamから読み取る適切な方法は、次のとおりです。

int len;
byte[] buffer = new byte[4096];
while (-1 != (len = in.read(buffer))) {
  bos.write(buffer, 0, len);
}

読み取りは、入力ストリームに何も残っていないか、接続が閉じられている場合に-1を返し、その間、ネットワークをブロックして待機します。配列の読み取りは、シングルバイトを使用するよりもはるかにパフォーマンスが高くなります。

于 2010-06-14T15:41:19.717 に答える
0

メッセージ全体を一度に読んでいる場合は、isr.available()を予想されるコンテンツの長さと比較できます。これは私がそれをした方法です:

public byte[] readData(HttpURLConnection conn)
        throws IOException, InterruptedException {
    String _connlen = conn.getHeaderField("Content-Length");
    int connlen = Integer.parseInt(_connlen);
    InputStream isr = null;
    byte[] bytes = new byte[connlen];

    try {
        isr = conn.getInputStream();

        //security count that it doesn't begin to hang
        int maxcounter = 0;
        //wait till all data is avalibal, max 5sec
        while((isr.available() != connlen) && (maxcounter  < 5000)){
            Thread.sleep(1);
            maxcounter++;
        }
        //Throw if not all data could be read
        if(maxcounter >= 5000)
            throw new IllegalAccessError(); 

        //read the data         
        if(isr.read(bytes, 0, connlen) < 0)
            throw new IllegalAccessError();     


    } finally {
        if (isr != null)
            isr.close();
    }

    return bytes;
}
于 2011-04-13T12:48:41.413 に答える
0

見逃したかもしれませんが、コードの「入力」のデータ型は何ですか? 一般に、InputStreams で奇妙な点は、データが使用可能になるまで read( ... ) メソッドがブロックされ、そのデータのみが返される傾向があることです。実際には、EOFException を明示的に強制するまで、InputStream からの読み取りと ByteArrayInputStream またはその他の構造への追加を続ける必要があります。

于 2010-06-14T14:57:38.927 に答える