rpc调用无法获取异常信息解决

原本http请求的写法如下:
   

private static Executor httpExecutor;

    static {
        // 设置重试策略,自定义,不忽略任何异常(即:任何异常都会重试),参考:DefaultHttpRequestRetryHandler
        HttpRequestRetryHandler retryHandler = (IOException exception, int executionCount, HttpContext context) -> executionCount <= 2;
        HttpClient httpClient = HttpClientBuilder.create().setMaxConnTotal(2000).setMaxConnPerRoute(500).setRetryHandler(retryHandler).build();
        httpExecutor = Executor.newInstance(httpClient);
    }

     /**
     * aisd相关专用,超时时间200s
     * @param body
     * @param headers
     * @param uri
     * @return
     */
    public static String postRequestForAISD(String body, Map<String, String> headers, String uri) {
        log.info("POST {} {}, Headers: {}", uri, body, mapToKeyValue(headers));
        long beginTime = System.currentTimeMillis();
        try {
            Request httpRequest = Request.Post(uri).connectTimeout(50000).socketTimeout(50000).bodyString(body, ContentType.APPLICATION_JSON);
            if (headers != null && headers.size() > 0) {
                headers.forEach(httpRequest::addHeader);
            }
            String result = httpExecutor.execute(httpRequest).returnContent().asString(Consts.UTF_8);
            long endTime = System.currentTimeMillis();
            log.info("POST,uri:{},millis:{},params:{}, Headers: {},result:{}", uri,endTime-beginTime, body, mapToKeyValue(headers), result);
            return result;
        } catch (HttpResponseException e) {
            log.error("POST_HttpResponseException", e);
            throw new RuntimeException("接口调用失败[StatusCode:" + e.getStatusCode() + ", Msg:" + e.getMessage() + "]");
        } catch (IOException e) {
            log.error("POST_IOException", e);
            throw new RuntimeException("接口调用失败[" + e.getMessage() + "]");
        }
    }


上面的调用只能拿到不明确的错误信息,如下:
StatusCode:400, Msg:status code: 400, reason phrase: model_error]

但是直接curl调用外部接口却可以获取详细错误信息,实例如下:
{
  "error": {
    "message": "This model's maximum context length is 8192 tokens. However, you requested 8301 tokens (7277 in the messages, 1024 in the completion). Please reduce the length of the messages or completion.",
    "type": "invalid_request_error",
    "param": "messages",
    "code": "context_length_exceeded"
  }
}

问题:上面的http请求的代码为什么拿不到详细的错误信息?怎么处理才能拿到详细的错误信息?

核心是下面这行代码:
String result = httpExecutor.execute(httpRequest).returnContent().asString(Consts.UTF_8);

httpExecutor.execute(httpRequest)获取到Response,然后调用returnContent方法获取返回内容,
如果rpc请求返回的不是200,那么会抛出HttpResponseException异常,进入catch(HttpResponseException e)分支,抛出RuntimeException异常,提示接口调用失败。如果rpc请求返回的不是200,但是没有抛出HttpResponseException异常,那么会进入catch(IOException e)分支,同样抛出RuntimeException异常,提示接口调用失败。
因此,无论rpc请求返回的是什么状态码,都会抛出RuntimeException异常,导致接口调用失败。但不会获取失败的详情。
解决:修改为先获取returnResponse,然后获取返回实例:
 

  /**
     * aisd相关专用,超时时间200s
     * @param body
     * @param headers
     * @param uri
     * @return
     */
    public static String postRequestForAISD(String body, Map<String, String> headers, String uri) {
        log.info("POST {} {}, Headers: {}", uri, "", mapToKeyValue(headers));
        long beginTime = System.currentTimeMillis();
        try {
            Request httpRequest = Request.Post(uri).connectTimeout(50000).socketTimeout(50000).bodyString(body, ContentType.APPLICATION_JSON);
            if (headers != null && headers.size() > 0) {
                headers.forEach(httpRequest::addHeader);
            }
            Response execute = httpExecutor.execute(httpRequest);
            HttpResponse httpResponse = execute.returnResponse();
            // 获取响应状态码
            int statusCode = httpResponse.getStatusLine().getStatusCode();

            String result = "";
            // 如果响应状态码不是200,则表示请求出错
            if (statusCode != 200) {
                // 获取错误信息
                String errorResponse = EntityUtils.toString(httpResponse.getEntity());
                log.info("errorResponse:"+errorResponse);
                throw new RuntimeException("接口调用失败[StatusCode:" + statusCode + ", Msg:" + errorResponse + "]");
            } else {
                result  = EntityUtils.toString(httpResponse.getEntity());;
            }
            long endTime = System.currentTimeMillis();
            log.info("POST,uri:{},millis:{},params:{}, Headers: {},result:{}", uri,endTime-beginTime, body, mapToKeyValue(headers), result);
            return result;
        } catch (HttpResponseException e) {
            log.error("POST_HttpResponseException", e);
            throw new RuntimeException("接口调用失败[StatusCode:" + e.getStatusCode() + ", Msg:" + e.getMessage() + "]");
        } catch (IOException e) {
            log.error("POST_IOException", e);
            throw new RuntimeException("接口调用失败[" + e.getMessage() + "]");
        }
    }

什么具体场景会让Response的返回内容是空,但HttpResponse的实体不为空呢?能给出具体的实例吗
有以下几种可能的场景:
1. 服务器返回的响应内容为空,这种情况下Response的返回内容是空的,但是HttpResponse的实体可能不为空,因为服务器可能会返回一些响应头信息或者状态码等其他信息。
2. 服务器返回的响应内容格式不正确,这种情况下Response的返回内容是空的,但是HttpResponse的实体可能不为空,因为服务器可能会返回一些错误信息或者其他格式不正确的内容。
3. 网络传输过程中出现异常,这种情况下Response的返回内容是空的,但是HttpResponse的实体可能不为空,因为网络传输过程中可能只传输了部分内容,或者传输过程中出现了错误,但是已经传输的内容仍然可以被获取。
例如,当使用HttpClient发送请求时,如果服务器返回的响应内容为空,但是响应头信息或者状态码不为空,那么Response的返回内容就是空的,但是HttpResponse的实体可能不为空,可以通过调用getEntity方法获取实体。