自分で作成した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でそれを見ることができます)
ありがとう
GetErrorStream()に関するJavaドキュメント)から:
接続が失敗したが、サーバーが有用なデータを送信した場合は、エラーストリームを返します。典型的な例は、HTTPサーバーが404で応答する場合です。これにより、接続時にFileNotFoundExceptionがスローされますが、サーバーは、何をすべきかについての提案を含むHTMLヘルプページを送信しました。この方法では、接続は開始されません。 接続が接続されていない場合、接続中にサーバーでエラーが発生しなかった場合、またはサーバーでエラーが発生したがエラーデータが送信されなかった場合、このメソッドはnullを返します。これがデフォルトです。
したがって、サーバーに到達しなかった場合(たとえば、不正なURL)、またはサーバーが応答で何も送信しなかった場合、getErrorStream()はnullを返します。
InputStream inputStream = null;
try {
inputStream = connection.getInputStream();
} catch(IOException exception) {
inputStream = connection.getErrorStream();
}
これは、応答ヘッダーのステータスコードを200を超える値に設定すると、接続オブジェクトがリセットされるようなものです。入力ストリームの取得中にSocketTimeoutExceptionを生成しますが、キャッチに入ると、とにかく入力ストリームを提供します。
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を呼び出すと、接続が閉じられます。 。
リクエストを実行する前にステートメント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();
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();
}