解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法
Posted 阿奇XS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法相关的知识,希望对你有一定的参考价值。
摘要: 大家知道, StringMVC中@RequestBody是读取的流的方式, 如果在之前有读取过流后, 发现就没有了.我们来看一下核心代码: filter中主要做的事情, 就是来校验请求是否合法, 是否有篡改过值.
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
if (Boolean.valueOf(authentication))
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
if (BasicdataCommonsConstant.POST.equalsIgnoreCase(httpServletRequest.getMethod()))
// 防止流读取一次后就没有了, 所以需要将流继续写出去
ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest);
String body = HttpHelper.getBodyString(requestWrapper);
if (StringUtils.isBlank(body))
LOGGER.error("非法请求, 没有APP_KEY, APP_SECRET");
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_ILLEGAL_FROMTYPE)));
return;
Map<String, String> parameters = gson.fromJson(body, new TypeToken<Map<String, String>>()
.getType());
String APP_KEY = parameters.get("appKey");
String APP_SECRET = parameters.get("appSecret");
TAuthUser authUser = authUserMap.get(APP_KEY);
if (authUser == null)
LOGGER.error("非法请求, 没有APP_KEY, APP_SECRET");
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_ILLEGAL_FROMTYPE)));
return;
else if (StringUtils.isBlank(APP_SECRET))
LOGGER.error("非法请求, APP_SECRET为空, user=", gson.toJson(authUser));
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_FROMTYPE_AND_KEY_CANNT_BE_NULL)));
return;
else if (!APP_SECRET.equals(authUser.getAppSecret()))
LOGGER.error("非法请求: 没有APP_KEY, APP_SECRET不匹配. user=, password=, name=", APP_KEY, APP_SECRET, authUser.getName());
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_ILLEGAL_KEY)));
return;
String SIGNATURE = parameters.get("signature");
// 对参数进行签名
String md5 = SignatureUtil.decryptSignature(parameters);
if (!md5.equals(SIGNATURE))
LOGGER.error("非法请求, signature =", SIGNATURE);
OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_SIGNATURE_ERROR)));
return;
threadLocalUser.setAuthUser(authUser);
chain.doFilter(requestWrapper, response);
chain.doFilter(request, response);
大家都知道, 流只能读一次, 读了就没有了, 为了后面的代码还能够取得流, 我们应该还需要将其写出去才行.
所以, 我新建立了一个类. 看代码:
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
/**
* Created with antnest-platform
* User: chenyuan
* Date: 12/31/14
* Time: 8:49 PM
*/
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper
private final byte[] body;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException
super(request);
body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
@Override
public BufferedReader getReader() throws IOException
return new BufferedReader(new InputStreamReader(getInputStream()));
@Override
public ServletInputStream getInputStream() throws IOException
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream()
@Override
public int read() throws IOException
return bais.read();
@Override
public boolean isFinished()
return false;
@Override
public boolean isReady()
return false;
@Override
public void setReadListener(ReadListener readListener)
;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created with antnest-platform
* User: chenyuan
* Date: 12/24/14
* Time: 10:39 AM
*/
public class HttpHelper
/**
* 获取请求Body
*
* @param request
* @return
*/
public static String getBodyString(ServletRequest request)
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null)
sb.append(line);
catch (IOException e)
e.printStackTrace();
finally
if (inputStream != null)
try
inputStream.close();
catch (IOException e)
e.printStackTrace();
if (reader != null)
try
reader.close();
catch (IOException e)
e.printStackTrace();
return sb.toString();
这样子就应该差不多了哦~
以上是关于解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法的主要内容,如果未能解决你的问题,请参考以下文章
Spring专题「Web请求读取系列」如何构建一个可重复读取的Request的流机制
#yyds干货盘点#☕并发技术系列「Web请求读取系列」如何构建一个可重复读取的Request的流机制