一、导入依赖库
因为 Hutool 工具包带有XSS转义的工具类,所以我们要导入 Hutool ,然后利用 Servlet 规范
提供的请求包装类,定义数据转义功能。
导入maven 依赖

<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.0</version>
</dependency>

二、实现代码

我们平时写Web项目遇到的 HttpServletRequest ,它其实是个接口。如果我们想要重新定义请
求类,扩展这个接口是最不应该的。因为 HttpServletRequest 接口中抽象方法太多了,我们逐
一实现起来太耗费时间。所以我们应该挑选一个简单一点的自定义请求类的方式。那就是继承
HttpServletRequestWrapper 父类。
JavaEE只是一个标准,具体的实现由各家应用服务器厂商来完成。比如说 Tomcat 在实现
Servlet 规范的时候,就自定义了 HttpServletRequest 接口的实现类。同时JavaEE规范还定义了 HttpServletRequestWrapper ,这个类是请求类的包装类,用上了装饰器模式。无论各家应用服务器厂商怎么去实现 HttpServletRequest 接口,
用户想要自定义请求,只需要继承 HttpServletRequestWrapper ,对应覆盖某个方法即可,然后
把请求传入请求包装类,装饰器模式就会替代请求对象中对应的某个方法。用户的代码和服务器
厂商的代码完全解耦,我们不用关心 HttpServletRequest 接口是怎么实现的,借助于包装类我
们可以随意修改请求中的方法。

代码包含大部分常用的方法

package com.wx.config.xss;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.json.JSONUtil;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (!StrUtil.hasEmpty(value)) {
            value = HtmlUtil.filter(value);
        }
        return value;
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                String value = values[i];
                if (!StrUtil.hasEmpty(value)) {
                    value = HtmlUtil.filter(value);
                }
                values[i] = value;
            }
        }
        return values;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> parameters = super.getParameterMap();
        Map<String, String[]> map = new LinkedHashMap<>();
        if (parameters != null) {
            for (String key : parameters.keySet()) {
                String[] values = parameters.get(key);
                for (int i = 0; i < values.length; i++) {
                    String value = values[i];
                    if (!StrUtil.hasEmpty(value)) {
                        value = HtmlUtil.filter(value);
                    }
                    values[i] = value;
                }
                map.put(key, values);
            }
        }
        return map;
    }

    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (!StrUtil.hasEmpty(value)) {
            value = HtmlUtil.filter(value);
        }
        return value;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        InputStream in = super.getInputStream();
        StringBuffer body = new StringBuffer();
        InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
        BufferedReader buffer = new BufferedReader(reader);
        String line = buffer.readLine();
        while (line != null) {
            body.append(line);
            line = buffer.readLine();
        }
        buffer.close();
        reader.close();
        in.close();
        Map<String, Object> map = JSONUtil.parseObj(body.toString());
        Map<String, Object> resultMap = new HashMap(map.size());
        for (String key : map.keySet()) {
            Object val = map.get(key);
            if (map.get(key) instanceof String) {
                resultMap.put(key, HtmlUtil.filter(val.toString()));
            } else {
                resultMap.put(key, val);
            }
        }
        String str = JSONUtil.toJsonStr(resultMap);
        final ByteArrayInputStream bain = new ByteArrayInputStream(str.getBytes());
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bain.read();
            }

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

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

            @Override
            public void setReadListener(ReadListener listener) {
            }
        };
    }
}

四、创建过滤器,把所有请求对象传入包装类

package com.wx.config.xss;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class XssFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain
            chain)
            throws IOException, ServletException {
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
                (HttpServletRequest) request);
        chain.doFilter(xssRequest, response);
    }

    @Override
    public void destroy() {
    }
}

另外 不要忘记
在springboot主类上 增加注解@ServletComponentScan

SpringBootApplication 上使用@ServletComponentScan 注解后
Servlet可以直接通过@WebServlet注解自动注册
Filter可以直接通过@WebFilter注解自动注册
Listener可以直接通过@WebListener 注解自动注册


分割线
测试业务的时候都正常。后面测中文场景踩雷了。
踩了坑。
在这里插入图片描述
没加上面的代码中文请求也是正常的。
加了上面的代码后中文请求就这样了。
贴一下报错:org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error。。。。。。。。。。。。。。。。。。。。。。。
看了好多帖子 都在说字符集问题,然后就去排查了好久 最后发现图里那个
IDAE配置:全局编码 GBK 改成UTF-8就好了。
在这里插入图片描述

搜了好多贴。也没弄明白这里的IDEA设置中得全局编码和项目编码的区别(以及为什么会触发这个坑)。
欢迎各位大佬评论。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐