解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法

我们来看一下核心代码: 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;
        BufferedInputStream bufferedInput = null;
        try {
            inputStream = request.getInputStream();
            bufferedInput = new BufferedInputStream(inputStream);

            byte[] buffer = new byte[1024];
            int bytesRead = -1;
            while ((bytesRead = bufferedInput.read(buffer)) != -1) {
                String chunk = new String(buffer, 0, bytesRead);
                sb.append(chunk);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bufferedInput != null) {
                try {
                    bufferedInput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
}

请注意这里的编码, 最好将其转换成UTF-8的编码格式, 不然你获取到的中文则会使乱码的. 我自己也习惯于UTF-8的编码.

这样子就应该差不多了哦~

时间: 2024-10-23 11:45:06

解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法的相关文章

解决在mysql表中删除自增id数据后,再添加数据时,id不会自增1的问题

https://blog.csdn.net/shaojunbo24/article/details/50036859 问题:mysql表中删除自增id数据后,再添加数据时,id不会紧接.比如:自增id 1 2 3 4 现在删除4,就变成了 1 2 3 这时候,如果增加一条数据,会变成 1 2 3 5 上面5不是我们想要的结果,4才是理想的id,解决方法是,在删除4之后,执行下面的sql语句: ALTER TABLE table_name AUTO_INCREMENT = 1; 原文地址:http

SpringMVC中redirect跳转后如何保存Model中的数据?

@RequestMapping(value = "delete-user", method = RequestMethod.POST) public String deleteUser(Long[] userId, RedirectAttributes modelMap) { userService.deleteUser(userId); modelMap.addFlashAttribute("resultMsg", "删除成功"); retur

解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题

首先我们来描述一下在开发中遇到的问题,场景如下: 比如我们要拦截所有请求,获取请求中的某个参数,进行相应的逻辑处理:比如我要获取所有请求中的公共参数 token,clientVersion等等:这个时候我们通常有两种做法 前提条件是我们实现Filter类,重写doFilter方法 1.通过getParameter方法获得 HttpServletRequest hreq = (HttpServletRequest) req; String param = hreq.getParameter("pa

ASP.NET Core 中读取 Request.Body 的正确姿势

ASP.NET Core 中的 Request.Body 虽然是一个 Stream ,但它是一个与众不同的 Stream —— 不允许 Request.Body.Position=0 ,这就意味着只能读取一次,要想多次读取,需要借助 MemoryStream ,详见博问 asp.net core中2次读取Request.Body的问题 using (var buffer = new MemoryStream()) { Request.Body.CopyTo(buffer); buffer.Pos

java读取request中的xml

java读取request中的xml 答: // 读取xml InputStream inputStream; StringBuffer sb = new StringBuffer(); inputStream = request.getInputStream(); String s; BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); while ((s = in.r

spring boot拦截器中获取request post请求中的参数

最近有一个需要从拦截器中获取post请求的参数的需求,这里记录一下处理过程中出现的问题. 首先想到的就是request.getParameter(String )方法,但是这个方法只能在get请求中取到参数,post是不行的,后来想到了使用流的方式,调用request.getInputStream()获取流,然后从流中读取参数,如下代码所示: String body = ""; StringBuilder stringBuilder = new StringBuilder(); Buf

java 读取数据库中文信息,为何在jsp页面中出现乱码

有如下几种解决办法: 1.保证项目的字符编码和每一个jsp页面的字符编码一致,如果不一致可能导致中文乱码问题<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %><meta http-equiv="Content-Type" content="text/html; charset=

浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂

var num = 1;    var str = '1';    var test = 1;    test == num  //true 相同类型 相同值    test === num //true 相同类型 相同值    test !== num //false test与num类型相同,其值也相同, 非运算肯定是false    num == str  //true 把str转换为数字,检查其是否相等.    num != str  //false == 的 非运算    num ==

nginx、Apache、IIS中413 Request Entity Too Large问题解决方法

分享下nginx.Apache.IIS三种服务器解决413 Request Entity Too Large问题的方法. 一.nginx服务器 nginx出现这个问题的原因是请求实体太长了.一般出现种情况是Post请求时Body内容Post的数据太大了,如上传大文件过大.POST数据比较多. 处理方法在nginx.conf增加 client_max_body_size的相关设置, 这个值默认是1m,可以增加到8m以增加提高文件大小限制:当然可以设置的更大点.# 在http,server或者loc