当前位置:   article > 正文

HttpURLConnection InputStream 读取非200响应码,错误的getInputStream_connection code not 200

connection code not 200

更多精彩

更多精彩请访问:http://www.gzdangfu.com

背景:

服务端项目中通过全局异常拦截器进行异常处理,但进行单元测试发现用java原生HttpURLConnection方法访问服务端时,无法读取到处理异常后的响应体中的内容,直接报错!在此记录下解决方案!

一、错误场景还原

先看看发生报错时的代码如何写的:

抛出自定义错误的代码:

try {
    service = (MoerService) SpringContextHolder.getBean(serviceImpl);
} catch (Exception e) {
    throw new SystemException(ErrorMessageConstants.NOT_BEAN_ERROR);
}
  • 1
  • 2
  • 3
  • 4
  • 5
全局异常拦截器:
/**
 * 全局异常拦截器
 *
 * @Author ---
 * @Date: --
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);


    /**
     * 拦截全局异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Result exception(Exception e) {
        logger.error("异常错误:", e);
        return Result.fail(ErrorMessageConstants.ABNORMAL_ERROR);
    }

    /**
     * 拦截系统异常
     */
    @ExceptionHandler(SystemException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Result systemException(SystemException e) {
        logger.error("系统异常:", e);
        return Result.fail(e.getMessage());
    }

    /**
     * 拦截业务异常
     */
    @ExceptionHandler(BussinessException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public Result bussinessException(BussinessException e) {
        logger.error("业务异常:", e);
        return Result.fail(e.getMessage());
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

HttpRequestUtil工具类方法(用来向服务端发起请求):

public static String postJsonParams(String requestUrl, String requestMethod, String params) {
   StringBuilder sb = new StringBuilder();
   try {
      URL url = new URL(requestUrl);// 创建连接
      HttpURLConnection connection = (HttpURLConnection) url
            .openConnection();
      connection.setDoOutput(true);
      connection.setDoInput(true);
      connection.setUseCaches(false);
      connection.setInstanceFollowRedirects(true);
      connection.setRequestMethod(requestMethod); // 设置请求方式
      connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式
      connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式
      connection.connect();
      OutputStreamWriter out = new OutputStreamWriter(
            connection.getOutputStream(), "UTF-8"); // utf-8编码
      out.append(params);
      out.flush();
      out.close();
      if (connection != null) {
         BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
         String line = null;
         while ((line = br.readLine()) != null) {
            sb.append(line);
            sb.append("\r\n");
         }
         br.close();
      }
      connection.disconnect();
   } catch (IOException e) {
      e.printStackTrace();
   }
   return sb.toString();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

当服务端抛出 SystemException() 时,会被异常拦截器 GlobalExceptionHandler 所处理,然后return
Result.fail(e.getMessage()),返回自定义友好错误提示;

但通过postJsonParams方法发起请求时,却无法获取服务端响应内容,报错信息如下:

java.io.IOException: Server returned HTTP response code: 500 for URL: http://localhost:8885/moerService/access
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1839)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1440)
	at com.moerlong.service_authorize.util.HttpRequest.postJsonParams(HttpRequest.java:94)
	at com.moerlong.service_authorize.controller.AccessController.test(AccessController.java:91)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

二、错误定位

由错误信息可以看到:Server returned HTTP response code: 500,说明服务端响应码为500是错误的源头;
  • 1

我们再看异常拦截器中的 @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 正好为response设置响应码为500,难道是这个问题?

之前通过HttpClient发送请求时没遇到这种问题,难道是HttpURLConnection API不能读取responseCode为500时的响应体内容么?

再看读取响应体的方法:

if (connection != null) {
         BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
         String line = null;
         while ((line = br.readLine()) != null) {
            sb.append(line);
            sb.append("\r\n");
         }
         br.close();
      }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我们是通过connection.getInputStream()方法获取输入流来读取响应体内容的!但这个API只能读取
responseCode=200 时的响应内容!

我们翻阅 HttpURLConnection 的API文档,可以看到十分靠前的一个方法getErrorStream()

在这里插入图片描述

Returns the error stream if the connection failed but the server sent
useful data nonetheless.

原来通过这个方法我们才能获取到responseCode不为200(connection failed)的响应内容(useful data)

三、解决方案

修改下HttpRequestUtil发送请求的工具类:
public static String postJsonParams(String requestUrl, String requestMethod, String params) {
   StringBuilder sb = new StringBuilder();
   try {
      URL url = new URL(requestUrl);// 创建连接
      HttpURLConnection connection = (HttpURLConnection) url
            .openConnection();
      connection.setDoOutput(true);
      connection.setDoInput(true);
      connection.setUseCaches(false);
      connection.setInstanceFollowRedirects(true);
      connection.setRequestMethod(requestMethod); // 设置请求方式
      connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式
      connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式
      connection.connect();
      OutputStreamWriter out = new OutputStreamWriter(
            connection.getOutputStream(), "UTF-8"); // utf-8编码
      out.append(params);
      out.flush();
      out.close();
      if (connection != null) {
         InputStream inputStream = null;
         //根据responseCode来获取输入流,此处错误响应码的响应体内容也要获取(看服务端的返回结果形式决定)
         if (HttpURLConnection.HTTP_OK == connection.getResponseCode()) {
            inputStream = connection.getInputStream();
         } else {
            inputStream = connection.getErrorStream();
         }
         BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
         String line = null;
         while ((line = br.readLine()) != null) {
            sb.append(line);
            sb.append("\r\n");
         }
         br.close();
      }
      connection.disconnect();
   } catch (IOException e) {
      e.printStackTrace();
   }
   return sb.toString();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

核心:

if (HttpURLConnection.HTTP_OK == connection.getResponseCode()) {
  inputStream = connection.getInputStream();
} else {
   inputStream = connection.getErrorStream();
}
  • 1
  • 2
  • 3
  • 4
  • 5

根据 ResponseCode来选择getInputStream/getErrorStream API即可!

作者免费源码福利,更多推荐,欢迎下载学习

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/668762
推荐阅读
相关标签
  

闽ICP备14008679号