简体   繁体   English

通过自定义 HttpServletRequestWrapper 发送请求时出现 IOException

[英]IOException when sending request through custom HttpServletRequestWrapper

I have a Gateway implementation, which redirects requests, but also I'm adding a capability to decrypt the body of the received request.我有一个网关实现,它重定向请求,但我还添加了解密接收到的请求正文的功能。 The thing is that I've found a lot of answers here on SO with instructions to implement it, wrapping the original request, but in some point, I do not know why, the request get lost before reaching the target and throws an IOException (the decryption works perfectly).问题是我在这里找到了很多关于 SO 的答案以及实现它的说明,包装了原始请求,但在某些时候,我不知道为什么,请求在到达目标之前丢失并抛出 IOException (解密工作完美)。 This is my implementation:这是我的实现:

public class MyRequestWraper extends HttpServletRequestWrapper {

public MyRequestWraper(HttpServletRequest request) {
    super(request);
}

@Override
public ServletInputStream getInputStream() throws IOException {
    try {
        String decryptedPayload = decryptPayload(getRequest().getInputStream(), getRequest().getCharacterEncoding());
        
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decryptedPayload.getBytes(getRequest().getCharacterEncoding()));
        return new ServletInputStream(){
            
            @SuppressWarnings("unused")
            private ReadListener readListener = null;
            
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
            
            @Override
            public void close() throws IOException {
                byteArrayInputStream.close();
            }
            
            @Override
            public int read(byte[] b, int off, int len) throws IOException {
                return byteArrayInputStream.read(b, off, len);
            }
            
            @Override
            public boolean isFinished() {
                return byteArrayInputStream.available() > 0;
            }
            
            @Override
            public boolean isReady() {
                return isFinished();
            }
            
            @Override
            public void setReadListener(ReadListener readListener) {
                this.readListener = readListener;
                if (!isFinished()) {
                    try {
                        readListener.onDataAvailable();
                    } catch (IOException e) {
                        readListener.onError(e);
                    }
                } else {
                    try {
                        readListener.onAllDataRead();
                    } catch (IOException e) {
                        readListener.onError(e);
                    }
                }
            }
            
        };
    } catch (Exception e) {
        e.printStackTrace();
        return super.getInputStream();
    }
}

@Override
public BufferedReader getReader() throws IOException {
    return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}

And this is the exception I get:这是我得到的例外:

org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: UT000128: Remote peer closed connection before all data could be read
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:243)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:225)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:201)

The wrapper instance is used inside a Filter implementation, so I'm passing in it to the "chain.doFilter" (and as I said, I can see that the decryption is executed and successful).包装器实例在过滤器实现中使用,因此我将其传递给“chain.doFilter”(正如我所说,我可以看到解密已执行并成功)。 Any clue will be appreciated.任何线索将不胜感激。

EDIT编辑
Also tried to use a byte[] instead of ByteArrayInputStream for the getInputStream() implementation, based on this comment基于此评论,还尝试使用byte[]而不是ByteArrayInputStream实现getInputStream()

Finally I made it work, the problem was with the content length of the request (keep in mind that my original request was encrypted, and the new input stream is decrypted, so the length differs).最后我成功了,问题出在请求的内容长度上(请记住,我的原始请求是加密的,而新输入的 stream 是解密的,所以长度不同)。 I have to overwrite the getContentLength method, and some other minor changes:我必须覆盖 getContentLength 方法,以及其他一些小改动:

public class MyRequestWraper extends HttpServletRequestWrapper {

private byte[] content;

public MyRequestWraper(HttpServletRequest request) {
    super(request);
    content = decryptPayload(getRequest().getInputStream(), getRequest().getCharacterEncoding());
}

@Override
public int getContentLength() {
    if (content != null) {
        return content.length;
    }
    return super.getContentLength();
}

@Override
public ServletInputStream getInputStream() throws IOException {
try {
    
    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content);
    return new ServletInputStream(){
        
        @SuppressWarnings("unused")
        private ReadListener readListener = null;
        
        @Override
        public int read() throws IOException {
            return byteArrayInputStream.read();
        }
        
        @Override
        public void close() throws IOException {
            byteArrayInputStream.close();
        }
        
        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            return byteArrayInputStream.read(b, off, len);
        }
        
        @Override
        public boolean isFinished() {
            return byteArrayInputStream.available() > 0;
        }
        
        @Override
        public boolean isReady() {
            return isFinished();
        }
        
        @Override
        public void setReadListener(ReadListener readListener) {
            this.readListener = readListener;
            if (!isFinished()) {
                try {
                    readListener.onDataAvailable();
                } catch (IOException e) {
                    readListener.onError(e);
                }
            } else {
                try {
                    readListener.onAllDataRead();
                } catch (IOException e) {
                    readListener.onError(e);
                }
            }
        }
        
    };
} catch (Exception e) {
    e.printStackTrace();
    return super.getInputStream();
}
}

@Override
public BufferedReader getReader() throws IOException {
    return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM