web-dev-qa-db-ja.com

HttpUrlConnectionのエラーストリーム

自分で作成したHTTPサーブレットに対してPOSTリクエストを実行したい。良いケース(HTTP応答コード200)は、URL.openConnection()メソッドを使用することで常に正常に機能します。エラー応答コード(例:400)の場合、HttpUrlConnection.getErrorStream()を使用する必要があると思いました。しかし、エラーの場合にサーブレットからデータを送り返していますが、ErrorStreamオブジェクトはnullです(このデータを評価してエラーメッセージを生成したい) 。これは私のコードがどのように見えるかです:

HttpURLConnection con = null;
        try {
            //Generating request String
            String request = "request="+URLEncoder.encode(xmlGenerator.getStringFromDocument(xmlGenerator.generateConnectRequest(1234)),"UTF-8");
            //Receiving HttpUrlConnection (DoOutput = true; RequestMethod is set to "POST")
            con = openConnection();
            if (con != null){
                PrintWriter pw = new PrintWriter(con.getOutputStream());
                pw.println(request);
                pw.flush();
                pw.close();
                InputStream errorstream = con.getErrorStream();

                BufferedReader br = null;
                if (errorstream == null){
                    InputStream inputstream = con.getInputStream();
                    br = new BufferedReader(new InputStreamReader(inputstream));
                }else{
                    br = new BufferedReader(new InputStreamReader(errorstream));
                }
                String response = "";
                String nachricht;
                while ((nachricht = br.readLine()) != null){
                    response += nachricht;
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

だから私の質問は、ステータスコードが400であるのになぜgetErrorStream()nullを返すのかということです(con.getInputStream()を呼び出すときにスローされるIOExceptionでそれを見ることができます)

ありがとう

19
Matthias Herbst

GetErrorStream()に関するJavaドキュメント)から:

接続が失敗したが、サーバーが有用なデータを送信した場合は、エラーストリームを返します。典型的な例は、HTTPサーバーが404で応答する場合です。これにより、接続時にFileNotFoundExceptionがスローされますが、サーバーは、何をすべきかについての提案を含むHTMLヘルプページを送信しました。この方法では、接続は開始されません。 接続が接続されていない場合、接続中にサーバーでエラーが発生しなかった場合、またはサーバーでエラーが発生したがエラーデータが送信されなかった場合、このメソッドはnullを返します。これがデフォルトです。

したがって、サーバーに到達しなかった場合(たとえば、不正なURL)、またはサーバーが応答で何も送信しなかった場合、getErrorStream()はnullを返します。

20
jeremy
InputStream inputStream = null;     
try {
    inputStream = connection.getInputStream();
} catch(IOException exception) {
   inputStream = connection.getErrorStream();
}

これは、応答ヘッダーのステータスコードを200を超える値に設定すると、接続オブジェクトがリセットされるようなものです。入力ストリームの取得中にSocketTimeoutExceptionを生成しますが、キャッチに入ると、とにかく入力ストリームを提供します。

10
nitin ashish

JDKコードを少し掘り下げて、ようやく理由を見つけました。 HttpURLConnection#getErrorStream()は、401または407を受信するとnullを返します。これは、抽象クラスのnoop実装が原因ではなく、ストリーミングモード(POST)のときに401/407が検出された場合、HttpURLConnectionが接続をすぐに閉じる/クリアするためです。 HttpURLConnectionの具体的な実装のソースを参照してください: http://grepcode.com/file/repository.grepcode.com/Java/root/jdk/openjdk/6-b14/Sun/net/www/protocol/ http/HttpURLConnection.Java#1079

とはいえ、getInputStream()を呼び出すときにIOExceptionをキャッチすると、サーバーへの接続はすでに閉じられ、下線付きのソケットがクリアされるため、getErrorStream()を呼び出すと常にnullになります。

多くの人が提案している他のオプションは、getInputStreamまたはgetErrorStreamを呼び出す前にステータスコードを確認することです。内部errorStreamはgetInputStreamを呼び出すときにのみ設定されるため、これは401と407にも当てはまりません。つまり、基本的にステータスコード!= 200の場合はinputStreamのコピーです。ただし、getInputStreamを呼び出すと、接続が閉じられます。 。

8
Daniel Wang

リクエストを実行する前にステートメントconn.setAllowUserInteraction(true);を入力すると、401ステータスを受け取っても、接続は閉じられません。

conn.setDoInput(true);
conn.setDoOutput(true);
conn.setAllowUserInteraction(true); //                <<<--- ### HERE
//do something
conn.connect();
boolean isError = (conn.getResponseCode() >= 400);
InputSteam is = isError ? con.getErrorStream() : con.getInputStream();
3
Paulo Ricardo

Androidドキュメント で提案されているように:

String responseString;
try {
    responseString = readInputStream(con.getInputStream());
} catch (final IOException e) {
    // This means that an error occurred, read the error from the ErrorStream
    try {
        responseString = readInputStream(con.getErrorStream());
    } catch (IOException e1) {
        throw new IllegalStateException("Unable to read error body.", e);
    }
}

private String readInputStream(final InputStream inputStream) throws IOException {
    final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    final StringBuilder responseString = new StringBuilder();
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        responseString.append(line);
    }
    bufferedReader.close();
    return responseString.toString();
}
1
hb0