HttpUrlConnection:如何获取非200 OK状态码的响应体

3

我试图从HttpUrlConnection对象获取响应主体,但当我的服务器没有返回200 OK时就会出现问题。在我的情况下,我得到了302重定向的响应,因此使用getInputStream()方法不起作用。我尝试使用getErrorStream()方法,但是由于某些原因,它给我返回了一个空对象。我为什么会得到getErrorStream()的空对象而不是实际的响应?

public static void main(String[] args) {
        String url = "http://www.google.com/";
        String proxy = "proxy.myproxy.com";
        String port = "8080";
        try {
            URL server = new URL(url);  
            Properties systemProperties = System.getProperties();
            systemProperties.setProperty("http.proxyHost",proxy);
            systemProperties.setProperty("http.proxyPort",port);
            HttpURLConnection connection = (HttpURLConnection)server.openConnection();
            connection.connect();
            System.out.println("Response code:" + connection.getResponseCode());
            System.out.println("Response message:" + connection.getResponseMessage());
            InputStream test = connection.getErrorStream();
            String result = new BufferedReader(new InputStreamReader(test)).lines().collect(Collectors.joining("\n"));
        } catch (Exception e) {
            System.out.println(e);
            System.out.println("error");
        } 
    }

在我的代码中,我看到的输出是:
Response code:302
Response message:Object Moved
java.lang.NullPointerException
error

具体来说,错误发生在我的尝试语句的最后一行,因为我的getErrorStream()返回了一个空对象,因此我得到了一个nullPointerException。有人熟悉这个吗?谢谢。
2个回答

4
因为302不被认为是错误的HTTP响应代码,所以它属于重定向响应,而不是客户端错误响应服务器错误响应
由于响应不以45开头,因此它不被视为错误响应。另请查看HttpURLConnection::getErrorStream文档:
返回错误流,如果连接失败但服务器仍然发送了有用的数据。典型例子是当HTTP服务器响应404时,在连接中会抛出FileNotFoundException,但服务器发送了带有建议的HTML帮助页面。
还可以查看源代码以获取更多信息并澄清一切。
@Override
public InputStream getErrorStream() {
    if (connected && responseCode >= 400) {
        // Client Error 4xx and Server Error 5xx
        if (errorStream != null) {
            return errorStream;
        } else if (inputStream != null) {
            return inputStream;
        }
    }
    return null;
}

很遗憾,这些信息并未包含在文档中。

那就可以解释了。谢谢!所以在这种情况下,getInputStream() 应该可以工作吗? - Tim
@Tim:是的,它应该可以工作。你必须根据HTTP响应代码执行一个动作-这就是它们被创建的原因。 - Nikolas Charalambidis
@Tim,你也可以看一下OpenJDK中的示例实现,这里很清楚为什么在你的情况下errorStream是空的HttpURLConnection - Piotr S
@NikolasCharalambidis 谢谢你分享这个,我真希望早些时候就看到了。 - buradd

0
package com.ketal.pos.sevice;


import com.utsco.model.User;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

/**
 *
 * @author Jose Luis Uyuni
 */
public class GenericService {

    private static final long serialVersionUID = 0L;

    public static final String HTTPS = "https";
    public static final String HTTP = "http";
    public String port;
    public static String protocolo = HTTP + "://";
    public String dominio;
    private String urlBase = protocolo;
    public String urlService;
    public Integer response;

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public String getDominio() {
        return dominio;
    }enter code here

    public void setDominio(String dominio) {
        this.dominio = dominio;
    }

    public String getUrlBase() {
        return urlBase;
    }

    public String getUrlService() {
        return urlService;
    }

    public void setUrlService(String urlService) {
        this.urlService = urlService;
    }

    public String getStringResponse(User u, String method, String query, String body) throws MalformedURLException, IOException, Exception {
        String response = null;
        this.urlBase = protocolo + dominio + urlService + query;
        URL url = new URL(urlBase);
        HttpURLConnection conn;
        if (protocolo.contains(HTTPS)) {
            conn = (HttpsURLConnection) url.openConnection();
        } else {
            conn = (HttpURLConnection) url.openConnection();
        }
        conn.setRequestMethod(method);
        conn.setRequestProperty("Accept", "application/json");
        conn.setRequestProperty("content-type", "application/json; charset=UTF-8");
        if (u != null) {
            conn.setRequestProperty("Authorization", "Basic " + javax.xml.bind.DatatypeConverter.printBase64Binary(("ketal.org" + ":" + "124578").getBytes()));
        }

        if (!method.equalsIgnoreCase("GET")) {
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Length", Integer.toString(body.length()));
            conn.setRequestProperty("body", body);
        }

        response = "";
        if (conn.getResponseCode() != 200) {
            if (conn.getErrorStream() != null) {
                response = getResponse(conn.getErrorStream());
            }

            
            if (response.equals("")) {
                response = "{\"message\": \"error\" , \"state\": \"error\", \"nroErr\" ;\"" + "0" + "\" }]";
            }
            
        } else {
            response = getResponse(conn.getInputStream());
        }

        conn.disconnect();
        return response;
    }

    public String getResponse(InputStream i) throws IOException {
        String res = "";
        InputStreamReader in = new InputStreamReader(i);
        BufferedReader br = new BufferedReader(in);
        String output;
        while ((output = br.readLine()) != null) {
            res += (output);
        }

        return res;
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接