解決在Filter中讀取Request中的流後, 然後再Control中讀取不到的做法
阿新 • • 發佈:2018-11-01
摘要: 大家知道, 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(); } }
這樣子就應該差不多了哦~