springboot在过滤器filter 获取request中post的数据和获取response的数据问题

项目中需要在filter处理一些post请求的数据和response的响应数据,比如数据解密,重复提交验证

 

在项目中,涉及到了内外网,且内外网不是通过端口映射来同步数据而是多加了一层网闸,考虑到用户体验问题,进行了一个请求保存,通过网闸将本次请求传到内网再请求一次,达到内外网数据一致(涉及了ID预设问题)


request和response的流只能获取一次,如果在filter中获取了以后,controller会报错(类似于Miss body),而response会没有响应值

 

解决方法:

request请求处理:

需要定义一个继承HttpServletRequestWrapper类的RequestWrapper

public class RequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = this.toByteArray(request.getInputStream());
    }

    private byte[] toByteArray(ServletInputStream inputStream) throws IOException {
        ByteArrayOutputStream out=new ByteArrayOutputStream();
        byte[] buffer=new byte[1024*4];
        int n=0;
        while((n= inputStream.read(buffer))!=-1){
            out.write(buffer,0,n);
        }
        return out.toByteArray();
    }

    @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 boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }

    public byte[] getBody() {
        return body;
    }

    public void setBody(byte[] data){
        body=data;
    }
}

request请求处理:

需要定义一个继承HttpServletRequestWrapper类的RequestWrapper

public class ResponseWrapper extends HttpServletResponseWrapper {
    private ByteArrayOutputStream byteArrayOutputStream;
    private ServletOutputStream servletOutputStream;
    private PrintWriter writer;



    public ResponseWrapper(HttpServletResponse response) {
        super(response);
        byteArrayOutputStream=new ByteArrayOutputStream();
        servletOutputStream=new WapperedOutputStream(byteArrayOutputStream);
        writer = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream,StandardCharsets.UTF_8));
    }

    @Override
    public ServletOutputStream getOutputStream(){
        return servletOutputStream;
    }

    @Override
    public PrintWriter getWriter() {
        return writer;
    }

    @Override
    public void flushBuffer(){
        if (servletOutputStream!=null){
            try {
                servletOutputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (writer!=null)
            writer.flush();
    }

    @Override
    public void reset() {
        byteArrayOutputStream.reset();
    }

    public String getResponseData(String charset) throws IOException {
        flushBuffer();
        byte[] bytes = byteArrayOutputStream.toByteArray();
        return new String(bytes,charset);
    }

    private class WapperedOutputStream extends ServletOutputStream{

        private ByteArrayOutputStream bos;

        public WapperedOutputStream(ByteArrayOutputStream stream){
            bos = stream;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {

        }

        @Override
        public void write(int b){
            bos.write(b);
        }
    }

    public byte[] getContent(){
        flushBuffer();
        return byteArrayOutputStream.toByteArray();
    }
}

在过滤器中将ServletRequest替换成RequestWrapper

在过滤器中将ServletResponse替换成ResponseWrapper

public class RequestWrapperFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
        ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletResponse);
        //获取post的值
        String body = IOUtils.toString(requestWrapper.getBody(), "UTF-8");
        //中间处理操作省略,生成newBody
        String newBody= .......//省略代码
        //修改body以后,想将修改body的值传入到RequestWrapper,如果没有修改,则可以无视,我这里要预设id
        requestWrapper.setBody(newBody);

        
        filterChain.doFilter(requestWrapper,responseWrapper);
        byte[] content = responseWrapper.getContent();
        //获取response的值
        String responseData = IOUtils.toString(content, "UTF-8");
        
        //注意 此处是servletResponse 不是responseWrapper,写responseWrapper的话 依旧响应不了
        ServletOutputStream outputStream = servletResponse.getOutputStream();
        outputStream.write(content);
        outputStream.flush();
        outputStream.close();
    }
}

同理,若后续需要用到post数据的话,类似于aop保存日志之类的,也是需要用RequestWrapper对request进行包装,然后从requesWrapper中获取数据

 RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
 String body = IOUtils.toString(requestWrapper.getBody(), "UTF-8");

 

<think>嗯,用户问的是如何正确使用Filter处理UTF-8编码数据。首先,我需要回忆一下Java Web开发中处理编码的常见方法。记得以前遇到过类似的问题,当表单提交数据时,如果编码设置不正确,会出现乱码。特别是GETPOST请求的处理方式不同。 根据用户提供的引用,特别是引用[4],使用Filter来处理统一编码是一个有效的方法。POST请求可以通过request.setCharacterEncoding("UTF-8")来设置,但GET请求的编码处理可能需要不同的方式,因为Tomcat对GET请求的参数解码默认使用ISO-8859-1。所以,在Filter里,除了处理POST,还需要对GET请求的参数进行重新编码。 接下来,我需要考虑如何编写一个Filter。首先,创建一个实现Filter接口的类,然后在doFilter方法中设置请求响应的编码。对于请求,如果是POST,直接设置setCharacterEncoding;如果是GET,可能需要手动对每个参数进行解码重新编码。不过,用户提到的引用[4]中说GET方式提交也能通过Filter解决,但实际中可能需要额外的处理步骤,比如在Tomcat的server.xml中配置URIEncoding为UTF-8,或者在Filter里对参数进行重新编码。 另外,引用的内容提到在过滤器中设置编码,这样在Servlet处理之前就已经正确解码了数据。同时,需要确保响应也使用UTF-8编码,可能需要设置response的字符编码内容类型。 然后,还要考虑配置Filter的web.xml部分,确保所有的请求都经过这个Filter处理。例如,将Filter映射到所有的URL模式,如/*。 用户提供的示例引用中,引用[1]引用[4]都提到在Filter里设置编码,但GET请求可能需要额外的处理。因此,正确的做法应该是在Filter中处理POST的编码,同时配置Tomcat的URIEncoding为UTF-8来处理GET请求的参数,或者在Filter中对GET请求的参数进行手动转码。 总结步骤的话,应该是:创建Filter,设置请求编码为UTF-8(针对POST),处理GET请求的参数编码,设置响应编码,配置web.xml,以及调整Tomcat的配置。同时,确保所有的JSP页面前端表单也使用UTF-8编码,避免不一致的问题。</think>### 如何正确使用 Filter 处理 UTF-8 编码数据? #### 1. **Filter 的核心作用** FilterJava Web 开发中用于预处理请求后处理响应的组件。在处理 UTF-8 编码时,Filter 主要用于: - **统一请求编码**:确保请求参数(POST/GET)按 UTF-8 解码 - **统一响应编码**:强制响应内容以 UTF-8 编码返回[^4] --- #### 2. **具体实现步骤** **步骤 1:创建 Filter 类** ```java public class EncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 设置请求编码(处理POSTrequest.setCharacterEncoding("UTF-8"); // 处理GET请求参数(需配合容器配置) if (request instanceof HttpServletRequest) { HttpServletRequest httpRequest = (HttpServletRequest) request; if ("GET".equalsIgnoreCase(httpRequest.getMethod())) { // 对参数进行二次解码(需容器支持) Map<String, String[]> params = httpRequest.getParameterMap(); for (Map.Entry<String, String[]> entry : params.entrySet()) { String[] values = entry.getValue(); for (int i = 0; i < values.length; i++) { values[i] = new String(values[i].getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); } } } } // 设置响应编码 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=UTF-8"); chain.doFilter(request, response); } } ``` **步骤 2:配置 web.xml** ```xml <filter> <filter-name>EncodingFilter</filter-name> <filter-class>com.example.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` --- #### 3. **关键注意事项** 1. **GET 请求的特殊处理**: - Tomcat 默认使用 `ISO-8859-1` 解码 URL 参数,需在 `server.xml` 中配置: ```xml <Connector port="8080" URIEncoding="UTF-8" ... /> ``` - 或通过代码手动转码(如步骤 1 中的示例)[^1][^4] 2. **前端页面一致性**: - JSP 页面需声明编码: ```jsp <%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> ``` - HTML 表单添加编码声明: ```html <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> ``` 3. **容器级配置**: - 在 IDE(如 IntelliJ)中设置 VM 参数: ``` -Dfile.encoding=UTF-8 ``` - 确保编译参数包含 UTF-8 编码[^2][^3] --- #### 4. **验证流程** 1. **POST 请求测试**:通过表单提交中文内容,检查服务器端接收是否正常 2. **GET 请求测试**:通过 URL 传递中文参数,例如 `?name=测试` 3. **响应验证**:检查浏览器接收的页面编码是否为 UTF-8 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值