在将日志过滤器从使用javax.servlet.servlet-api:2.5
to调整3.0.1
为 Tomcat 时,我遇到了一个问题。
日志消息的一部分以 UTF-8 正确编码,而另一部分则存在一些编码问题(未知编码)。
问题:bufferedResponse.getContent()
返回一个奇怪编码的字符串
输出:
713901 [http-bio-8080-exec-7] ERROR com.example.filters.ReqRespDumpFilter - java.lang.NullPointerException
713962 [http-bio-8080-exec-7] DEBUG com.example.filters.ReqRespDumpFilter - REST Request - [HTTP METHOD:GET] [PATH INFO:null] [REQUEST PARAMETERS:{}] [REQUEST BODY:] [REMOTE ADDRESS:0:0:0:0:0:0:0:1] [RESPONSE: (�h�h& ��
�v
�00h�"00�.)00��7( �����������������������������������������������������������x��x�x���w�w�w������x��w�xx��x��wx�������������x�����������������������������������������������( @���������������������������������������������������������������������������q��e��l��n��f��s��n��n��y��p��q��n��y��u��n����q��|��n��k��d��]��W��]��X��C��J��N��V��O��<��5��*��,����|}~uz}ft~\mwYYY "$���BBBBBBBBBBBBBBBBBBBBB-BB,/4BB(=A'2:1BB?7379;8.%BB(38820BB
>65!$BB ,!#BB@
!BB&,*&+BB= <BBBBBBBBBBBBBBBBBBBBB��������������������������������( @��������������������������������������������������������������������������������������������������������������������嘥�d��������i����������������������Ӑ��W��N��������������~��tz~ "$������n��D��,��X�����������������\mw8��J��?��*����7��]��y����������������������I��4��4��A��]��q��e����������������������ft~O��V��s��p��n��n�㓙���������������������ݹ��m��l��p��q��n�݉�����������������YYY���������d��n��k��f��y��������������������������u��j�����|��q��n��������������������������vy{������������|}~�����������������������������������������������������������������������������������������������������������������������( @����������������������������������������������������������������������������������������������������������������x��������������x������������w������p��x��w������x��wwx�����x�����wwx�������w�wwww��������w��wwx�������x���www��������������ww�����������������������w���x�����������w�����������w�x�x���x������wxw�w�����x��xxwww�����w�����w��������������wx�����������w�x�����������������������x�������������������������������������������������������������������( @�������������������������������������������������������������p��c��i��a��c��i��j��k��d��Z��]��U��T��^��k��q��r��p��q��r��m��n��n��n��q��q��o��n��m��n��l��{��~��j��j��k��e��h��e��Q��J��B��K��G��K��O��X��Z��S��0��:��;��3��6��7��+��'��"��.����s|�oy�gx�gw�S}�^z�]v�Rz�Uv�Ss�{||qy~sssku{mptgqwjnranxbmtiiiccc]t~[ozXksVlxRhtUdiMbnZ_dLZbYYYQY^PWYUUUHX_FSZMMMCCC>DF<<<59:048+./���|||||||||||||||||||||||||||||||||||||||||
RBCp||l=D b@G@U
||B=nn
]AKJP||>ad|Zf>HHG]||b<t|q]X=KKNDo||V>Q
u||cSX>HLEENAV|| D=mTWYk>=GNLKHHKGTm||mGMMGTLENHHHHK=g5b||^;LKGXGHHHHHK?e#6||
TDGIHHNHNLGh9||
xGG>L=F=<g'$('`||Px@DoIAsv*+e0)jn ||
l|YOGg$/g0e2"_||
[CAV,,)17||Z:!1V/0e./||Zqn
6-,/4||
\||tZ.*/%)P||[*5( ]||P28+&{5*02]||32|c
Z|63||xwnz|| \Z
|||||||||||||||||||||||||||||||||||||||||( @�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gx�X��Y��PWYZ^cA��S�����������������������������������������������������������������cntJ��=��L��^z�������X��@��������������������������XXXXXX�����������������������뮮�iv}O��-��7��q|����������������K��anx���������������cccxxx��������������������Ո��[ozK��5��5��8��ju{������������������bovK��������������NNNSSS��������������۠��ksxUw�C��*��+��.��S��QY^������������������������Zv�J��oy����CCCjjj���������gw�Vv�K��5��'��0��0��,��O��_t�������������������������������T��G��K[eT�Rz�Ss�MbnK��B��8��.��'��-��1��3��-��9��Q|�OZ`������������������������������������IZa=��"��"��9��S{�'��0��-��4��3��3��3��*��C��Siui��`kq������������������������������������mptQ��'��+��8��Tv�;��4��3��3��3��3��*��G��[sq��X��b��m�������������������������������؟��������S~�R��;��7��0��3��.��3��.��'��<��Vlxp��X��a��]��_��h�����������������������������������������69:>��<��J��'��@��:��B��H��Qhts��Z��p��l��p��c��j��jnr���������������������������������������w}�048L��S��HX_4��O��FSZ>DFm��X��n��]s}m��_��l��Udi[[[�����������������㓓����������������������Z_dSr���9��Rhtt��`��m��Xksl��^t~k��c��k��gqw�����������������ꌌ����������������������������px}Z��N��]u�c��]��q��q��h��o��n��a��^��k��������������������������������������������������������zzze��^��l��n��_w�l��m��^t~o��b��n����������������������҉��������������VVVXXX������������h��f��d��h��q��k��a��q��o��f��m��~��������������������������������tttKKK���������y|~e��`��o��o��o��h��b��c��p��n��c��s{���������������������������������ٚ�����������������rze��X��d��n��i��j��n��X��U��T��d��jtz���������������������������������������������������q{�f��l��e��m��q��l��l��n��l��g��mw}���������������������������������������������������{��l��hhh��ó�����������{{{h��{��������������������������������������������������������49:<<<���������������������ZZZ+./���������������������������������������������������������qqq������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(0`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ww�����������������x�������������������x�wx��x�����������������w����x�������������w�w��px�������������ww���������pw����x��w�x��������������ww��������������www�x�����������wwwwx��������w���wwwwwwx�����������ww�wwwwwwx�����������www�wwwwww�������������ww�wwwwwx�p�����������wwwww��ww�����������wwwwww���x��������x�x�����xx�����������������x�x�������������������x�������������wx�p�����������������x�wxw��x���������������wx�w�w���������������p������������p��x�p����xw������������x�����������x�������x��ww�x��������x�������ww�w�x������������������wx��������������p��x����������������www�x�������������x�������������������p������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(0`�
���������������������������������������������������d��k��a��e��j��k��l��e��\��[��R��l��q��p��p��q��q��p��n��o��o��o��o��A��p��q��n��o��n��n��n��l��n��j��i��g��g��f��e��Q��I��K��D��J��M��Q��0��;��3��3��6��+��'��"��.��*��%��!����?��d~�a{�R|�_w�Sy�Sv�Sq�{{{tttat}kkkccc]r|[oyQl|WiqPfs_abUemUaeOfrNcn]^aQ]dL^hLZcHWaGX`GWa]^^TXZUUUHX_KU[LQTGT\IOTCMRKKKDJLAFJFFF>EK<CF9=A7>B<<<38:47:012.23./0*,.'))&')"
(the output is too long)
]
新添加的HttpServletResponse
in方法servlet-api:3.0.1
:
@Override
public int getStatus() {
return original.getStatus();
}
@Override
public String getHeader(String s) {
return original.getHeader(s);
}
@Override
public Collection<String> getHeaders(String s) {
return original.getHeaders(s);
}
@Override
public Collection<String> getHeaderNames() {
return original.getHeaderNames();
}
过滤器代码:
package com.example.filters;
import java.io.*;
import java.util.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.output.TeeOutputStream;
import org.apache.log4j.Logger;
public class ReqRespDumpFilter implements Filter {
private static final Logger logger = Logger.getLogger(ReqRespDumpFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
Map<String, String> requestMap = this.getTypesafeRequestMap(httpServletRequest);
BufferedRequestWrapper bufferedReqest = 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.getPathInfo())
.append("] [REQUEST PARAMETERS:")
.append(requestMap)
.append("] [REQUEST BODY:")
.append(bufferedReqest.getRequestBody())
.append("] [REMOTE ADDRESS:")
.append(httpServletRequest.getRemoteAddr())
.append("]");
chain.doFilter(bufferedReqest, bufferedResponse);
logMessage.append(" [RESPONSE:").append(bufferedResponse.getContent()).append("]");
logger.debug(logMessage);
} catch (Throwable a) {
logger.error(a);
}
}
private Map<String, String> getTypesafeRequestMap(HttpServletRequest request) {
Map<String, String> typesafeRequestMap = new HashMap<String, String>();
Enumeration<?> requestParamNames = request.getParameterNames();
while (requestParamNames.hasMoreElements()) {
String requestParamName = (String) requestParamNames.nextElement();
String requestParamValue = request.getParameter(requestParamName);
typesafeRequestMap.put(requestParamName, requestParamValue);
}
return typesafeRequestMap;
}
@Override
public void destroy() {
}
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 letti;
while ((letti = is.read(buf)) > 0) {
this.baos.write(buf, 0, letti);
}
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 = null;
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);
}
}
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);
}
public void flush() throws IOException {
super.flush();
this.targetStream.flush();
}
public void close() throws IOException {
super.close();
this.targetStream.close();
}
}
public class BufferedResponseWrapper implements HttpServletResponse {
HttpServletResponse original;
TeeServletOutputStream tee;
ByteArrayOutputStream bos;
public BufferedResponseWrapper(HttpServletResponse response) {
original = response;
}
public String getContent() { return bos.toString(); }
public PrintWriter getWriter() throws IOException {
return original.getWriter();
}
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 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 int getStatus() {
return 0;
}
@Override
public String getHeader(String s) {
return "unsupported";
}
@Override
public Collection<String> getHeaders(String s) {
return Collections.emptyList();
}
@Override
public Collection<String> getHeaderNames() {
return Collections.emptyList();
}
}
}