我正在尝试拦截并记录所有请求 - 响应。要使用RestTemplate.exchange()
发出请求。
当我发出GET
请求并收到4**
错误时,我可以致电ClientHttpResponse.getBody(
)并可以访问回复正文,但PUT
和{{1} } requests POST
方法抛出异常。
可能导致此问题的原因以及我如何获得ClientHttpResponse.getBody()
和POST
请求的响应正文?
这是我提出请求的地方:
PUT
这是获取异常的拦截器的一部分:
apiResponse = restTemplate.exchange(url, vCloudRequest.getHttpMethod(), entity, responseType);
这是堆栈。
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
String requestString = new String(body);
String responseString = new
// Below line throws exception
String(ByteStreams.toByteArray(response.getBody()), Charset.forName("UTF-8"));
更新:
当我在致电Caused by: java.io.IOException: Server returned HTTP response code: 403 for URL: https://176.235.57.11/api/admin/org/bd154aaf-2e7c-446d-91be-f0a45138476b/users
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1876)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at org.springframework.http.client.SimpleClientHttpResponse.getBody(SimpleClientHttpResponse.java:85)
at org.springframework.http.client.BufferingClientHttpResponseWrapper.getBody(BufferingClientHttpResponseWrapper.java:69)
at roma.api_utils.model.Interceptors.RequestLoggingInterceptor.intercept(RequestLoggingInterceptor.java:39)
at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:86)
at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:70)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:652)
之前致电response.getStatusCode()
时,它不会抛出response.getBody()
。
答案 0 :(得分:7)
基础知识:
HttpURLConnection
有两个相似的字段errorStream
和inputStream
,当我们调用其getInputSteam
方法时,它会检查响应是否有错误代码。如此,它抛出IOException
并记录它,这就是你获得异常的原因;此外,它还将inputStream
中的内容复制到errorStream
,因此我们可以获得其响应体通过调用getErrorStream
方法,这正是SimpleClientHttpResponse对getBody
方法的处理方式:
@Override
public InputStream getBody() throws IOException {
InputStream errorStream = this.connection.getErrorStream();
this.responseStream =
(errorStream != null ? errorStream : this.connection.getInputStream());
return this.responseStream;
}
首先检查errorStream
是否为空,如果为false,则返回,如果为真,则调用connection.getInputStream()
并返回
现在就是答案
response.getBody()
后调用response.getStatusCode()
并不会抛出IOException,这是因为getStatusCode
在内部调用了getInputStream
。因此,errorStream
将会调用getBody
时不为空org.springframework.http.client.SimpleBufferingClientHttpRequest#executeInternal
。。
@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput)
throws IOException {
addHeaders(this.connection, headers);
// JDK <1.8 doesn't support getOutputStream with HTTP DELETE
if (HttpMethod.DELETE == getMethod() && bufferedOutput.length == 0) {
this.connection.setDoOutput(false);
}
if (this.connection.getDoOutput() && this.outputStreaming) {
this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
}
this.connection.connect();
if (this.connection.getDoOutput()) {
FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
}
else {
// Immediately trigger the request in a no-output scenario as well
this.connection.getResponseCode();
}
return new SimpleClientHttpResponse(this.connection);
}
当http方法为GET时,它急切地执行this.connection.getResponseCode();
答案 1 :(得分:0)
我有类似的记录每个请求和响应的要求。我写了一个过滤器并挂钩过滤器链。
代码如下所示:
public class CustomRequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//No custom initialisation required
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
try {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
Map<String, String> requestMap = this
.getTypesafeRequestMap(httpServletRequest);
BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(
httpServletRequest);
BufferedResponseWrapper bufferedResponse = new BufferedResponseWrapper(
httpServletResponse);
final StringBuilder logMessage = new StringBuilder(
"REST Request - ").append("[HTTP METHOD:")
.append(httpServletRequest.getMethod())
.append("] [PATH INFO:")
.append(httpServletRequest.getServletPath())
.append("] [REQUEST PARAMETERS:").append(requestMap)
.append("] [REQUEST BODY:")
.append(bufferedRequest.getRequestBody())
.append("] [REMOTE ADDRESS:")
.append(httpServletRequest.getRemoteAddr()).append("]");
log.info("=======================REQUEST PAYLOAD=================================");
log.info(bufferedRequest.getRequestBody());
log.info("========================================================");
filterChain.doFilter(bufferedRequest, bufferedResponse);
logMessage.append(" [RESPONSE:")
.append(bufferedResponse.getContent()).append("]");
log.info("=======================REST RESPONSE=================================");
log.info(bufferedResponse.getContent());
log.info("========================================================");
} catch (Exception a) {
log.error("Error while filtering ", a);
}
}
private Map<String, String> getTypesafeRequestMap(HttpServletRequest request) {
Map<String, String> typesafeRequestMap = new HashMap<>();
Enumeration<?> requestParamNames = request.getParameterNames();
while (requestParamNames.hasMoreElements()) {
String requestParamName = (String) requestParamNames.nextElement();
String requestParamValue;
if ("password".equalsIgnoreCase(requestParamName)) {
requestParamValue = "********";
} else {
requestParamValue = request.getParameter(requestParamName);
}
typesafeRequestMap.put(requestParamName, requestParamValue);
}
return typesafeRequestMap;
}
@Override
public void destroy() {
//not yet implemented
}
private static final class BufferedRequestWrapper extends
HttpServletRequestWrapper {
private ByteArrayInputStream bais = null;
private ByteArrayOutputStream baos = null;
private BufferedServletInputStream bsis = null;
private byte[] buffer = null;
public BufferedRequestWrapper(HttpServletRequest req)
throws IOException {
super(req);
// Read InputStream and store its content in a buffer.
InputStream is = req.getInputStream();
this.baos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int read;
while ((read = is.read(buf)) > 0) {
this.baos.write(buf, 0, read);
}
this.buffer = this.baos.toByteArray();
}
@Override
public ServletInputStream getInputStream() {
this.bais = new ByteArrayInputStream(this.buffer);
this.bsis = new BufferedServletInputStream(this.bais);
return this.bsis;
}
String getRequestBody() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(
this.getInputStream()));
String line;
StringBuilder inputBuffer = new StringBuilder();
do {
line = reader.readLine();
if (null != line) {
inputBuffer.append(line.trim());
}
} while (line != null);
reader.close();
return inputBuffer.toString().trim();
}
}
private static final class BufferedServletInputStream extends
ServletInputStream {
private ByteArrayInputStream bais;
public BufferedServletInputStream(ByteArrayInputStream bais) {
this.bais = bais;
}
@Override
public int available() {
return this.bais.available();
}
@Override
public int read() {
return this.bais.read();
}
@Override
public int read(byte[] buf, int off, int len) {
return this.bais.read(buf, off, len);
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
//No specific readListener changes required
}
}
public class TeeServletOutputStream extends ServletOutputStream {
private final TeeOutputStream targetStream;
public TeeServletOutputStream(OutputStream one, OutputStream two) {
targetStream = new TeeOutputStream(one, two);
}
@Override
public void write(int arg0) throws IOException {
this.targetStream.write(arg0);
}
@Override
public void flush() throws IOException {
super.flush();
this.targetStream.flush();
}
@Override
public void close() throws IOException {
super.close();
this.targetStream.close();
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener writeListener) {
//not yet implemented
}
}
public class BufferedResponseWrapper implements HttpServletResponse {
HttpServletResponse original;
TeeServletOutputStream tee;
ByteArrayOutputStream bos;
public BufferedResponseWrapper(HttpServletResponse response) {
original = response;
}
public String getContent() {
return bos.toString();
}
@Override
public PrintWriter getWriter() throws IOException {
return original.getWriter();
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (tee == null) {
bos = new ByteArrayOutputStream();
tee = new TeeServletOutputStream(original.getOutputStream(),
bos);
}
return tee;
}
@Override
public String getCharacterEncoding() {
return original.getCharacterEncoding();
}
@Override
public String getContentType() {
return original.getContentType();
}
@Override
public void setCharacterEncoding(String charset) {
original.setCharacterEncoding(charset);
}
@Override
public void setContentLength(int len) {
original.setContentLength(len);
}
@Override
public void setContentLengthLong(long l) {
original.setContentLengthLong(l);
}
@Override
public void setContentType(String type) {
original.setContentType(type);
}
@Override
public void setBufferSize(int size) {
original.setBufferSize(size);
}
@Override
public int getBufferSize() {
return original.getBufferSize();
}
@Override
public void flushBuffer() throws IOException {
tee.flush();
}
@Override
public void resetBuffer() {
original.resetBuffer();
}
@Override
public boolean isCommitted() {
return original.isCommitted();
}
@Override
public void reset() {
original.reset();
}
@Override
public void setLocale(Locale loc) {
original.setLocale(loc);
}
@Override
public Locale getLocale() {
return original.getLocale();
}
@Override
public void addCookie(Cookie cookie) {
original.addCookie(cookie);
}
@Override
public boolean containsHeader(String name) {
return original.containsHeader(name);
}
@Override
public String encodeURL(String url) {
return original.encodeURL(url);
}
@Override
public String encodeRedirectURL(String url) {
return original.encodeRedirectURL(url);
}
@SuppressWarnings("deprecation")
@Override
public String encodeUrl(String url) {
return original.encodeUrl(url);
}
@SuppressWarnings("deprecation")
@Override
public String encodeRedirectUrl(String url) {
return original.encodeRedirectUrl(url);
}
@Override
public void sendError(int sc, String msg) throws IOException {
original.sendError(sc, msg);
}
@Override
public void sendError(int sc) throws IOException {
original.sendError(sc);
}
@Override
public void sendRedirect(String location) throws IOException {
original.sendRedirect(location);
}
@Override
public void setDateHeader(String name, long date) {
original.setDateHeader(name, date);
}
@Override
public void addDateHeader(String name, long date) {
original.addDateHeader(name, date);
}
@Override
public void setHeader(String name, String value) {
original.setHeader(name, value);
}
@Override
public void addHeader(String name, String value) {
original.addHeader(name, value);
}
@Override
public void setIntHeader(String name, int value) {
original.setIntHeader(name, value);
}
@Override
public void addIntHeader(String name, int value) {
original.addIntHeader(name, value);
}
@Override
public void setStatus(int sc) {
original.setStatus(sc);
}
@SuppressWarnings("deprecation")
@Override
public void setStatus(int sc, String sm) {
original.setStatus(sc, sm);
}
@Override
public String getHeader(String arg0) {
return original.getHeader(arg0);
}
@Override
public Collection<String> getHeaderNames() {
return original.getHeaderNames();
}
@Override
public Collection<String> getHeaders(String arg0) {
return original.getHeaders(arg0);
}
@Override
public int getStatus() {
return original.getStatus();
}
}
}
答案 2 :(得分:-1)
对于PUT
和POST
,它取决于您的目标资源。如果您的目标资源在PUT
或POST
请求后未在响应正文中添加任何内容,则获得异常是正常的。通常,您知道使用PUT
或POST
发送的资源,因此您只需检查响应的状态即可知道您的资源是否已创建或修改。您无需再次检查响应正文。
答案 3 :(得分:-1)
您可以使用以下内容访问拦截器中的响应主体。我做了一个快速的单元测试,以确认它甚至在具有403响应的POST上也能正常工作。
但是要小心,getBody会返回一个InputStream。这意味着您只能阅读一次。除非您使用新主体提供新响应,否则您将无法在拦截器外再次读取相同的流。
...
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
final ClientHttpResponse response = execution.execute(request, body);
final InputStream body = response.getBody();
return response;
}
...