工具使用集|Tomcat 有感(中)

Tomcat(中)知识使用- 重写URL

前言

距离上一次更新文章,已经有两个多月了。这次写这篇文章,也算是一次对读书的一种感悟。说实话,当我看完Tomcat的一部分知识之后。我发现我和读了没读,好像没有什么区别。如果,你问我相关的tomcat知识,我还可以零零散散的给出几句答复。但是更深入的运用却好像不行。而且,有段时间我也在纠结,我这样的读书学习是不是真的有效果。直到遇到这件事情,才让我知道读书的好处与学习的目的。

我发现学习书本,就对我而言。并不是要你立刻就会,一看就能用。读书的目的是让你有印象,让你知道遇到相关的困难和知识,可以帮你更快的了解。

问题描述

有一个需求问题,当访问 http://127.0.0.1:8080/xxx/a/homePage?PageId=1,是正常的。但是,用户可能会在/xxx/a上加入%20 可以造成404、未访问等原因。

http://127.0.0.1:8080/xxx/%20a/homePage?PageId=1

问题解决

可以使用的安全框架是shiro或者类似的安全框架来对url进行控制访问。但是,为了说明学习到的经验,我将从最简单的方式就是在请求进入时将请求的url拦截修改。(解决这种功能的方式很多)

简单来说将请求拦截的%20 或者 其他的转义字符去掉。但我们可以很正确的判断,用户可能会一不小心在url上面添加空格的操作,不过如果是其他操作,那么我们则可以认为用用户填写错误的url。所以,我对这些错误添加url的情况,不做讨论。

当用户访问 localhost:8091/employee /find 。一般普通的SpringBoot 会出现Mapping 映射问题,出现404

这种情况用户可能觉得烦(byd用户,多事)。那么,我们可以通过拦截请求将url进行修正。

当我们修改代码的时候,会发现HttpServletRequest(ServletRequest)它并不支持我们修改直接Url,然后替换回去。只允许我们从中获取一些信息,和添加一些信息。并不支持我们修改。此时,我们可能会感到困惑,经过查阅资料了解到,想要修改Url可以通过HttpServletRequestWrapper包装类,来进行修改。

HttpServletRequestWrapper是一个在Servlet编程中常用的包装类,它实现了HttpServletRequest接口,允许你对原始请求进行包装、定制和修改。通过继承自HttpServletRequestWrapper,你可以在请求处理的各个阶段对请求进行拦截、增强或修改,而不需要改变原始的Servlet代码。这种设计模式被称为装饰器模式。

  1. 请求参数的处理和修改: 你可以通过扩展HttpServletRequestWrapper来拦截请求参数,修改参数的值或者进行额外的验证操作。
  2. URL的修改和重定向: 借助HttpServletRequestWrapper,你可以修改请求的URL,进行重定向操作,或者对URL进行特定规则的处理。
  3. 请求头的定制: 如果需要向请求头中添加自定义的信息,或者根据请求头来做特定的处理,HttpServletRequestWrapper也是一个合适的选择。
  4. 请求内容的修改: 当需要对请求的内容进行加密、解密、压缩或其他变换时,也可以通过包装请求来实现这些需求。
typescript 复制代码
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
​
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private final Map<String, String[]> modifiedParameters;
​
    public CustomHttpServletRequestWrapper(HttpServletRequest request, Map<String, String[]> modifiedParameters) {
        super(request);
        this.modifiedParameters = new HashMap<>(modifiedParameters);
    }
​
    @Override
    public String getParameter(String name) {
        if (modifiedParameters.containsKey(name)) {
            String[] values = modifiedParameters.get(name);
            if (values != null && values.length > 0) {
                return values[0];
            }
        }
        return super.getParameter(name);
    }
​
    @Override
    public Map<String, String[]> getParameterMap() {
        return Collections.unmodifiableMap(modifiedParameters);
    }
​
    @Override
    public Enumeration<String> getParameterNames() {
        return Collections.enumeration(modifiedParameters.keySet());
    }
​
    @Override
    public String[] getParameterValues(String name) {
        return modifiedParameters.get(name);
    }
}
​
java 复制代码
@Component
public class UrlFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 获取原始的URL(带转义字符)
​
​
        try {
            // 使用URLDecoder来解码URL中的转义字符
            HttpServletRequest httpRequest = (HttpServletRequest) request;
​
            
​
            // 获取原始的URL(带转义字符)
            String encodedUrl = httpRequest.getServletPath();
​
            String regex = "%20|\s"; //如果单词使用这个正则表达式做比较可能会有问题,例如url参数中如果携带了%20,那么也会被移除。
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(encodedUrl);
​
            // 使用空字符串替换匹配到的字符
            String result = matcher.replaceAll("");
            // 创建一个包装器,以便修改URL
​
            HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper((HttpServletRequest) request) {
                @Override
                public String getRequestURI() {
                    return result; // 返回解码后的URL
                }
            };
​
            // 继续处理已修改的请求
            chain.doFilter(requestWrapper, response);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
​

如果此时,我并没有学习Tomcat相关的知识。虽然,我可以照葫芦画瓢,实现修改Url的功能。这样做并不能给我带来深刻的印象。但是,我们看了书,了解相关的知识。那么,当我们看到代码就知道了包装类,是的!Tomcat中很多地方使用包装类,并且还有装饰类。是为了帮助开发者更关注功能,缩小权限访问。这样我就对这些内容更加了解。

总结

因此,我学习Tomcat并不能快速的帮我解决这个问题。因为,学习并不总是瞬间见效的,它可能不会立即展现出明显的提升。然而,学习为我们打下了解决问题的基础,使得我们在遇到问题和解决问题的过程中得以游刃有余,融会贯通。

因此我明白,知识不仅是为了应付眼前,更是为了提升透视未来的能力,让我们在挑战面前能够自信从容。每一次的学习对我们来说并不都是受益匪浅的,但是我们的成长铺就了一条通往更高境界的道路。

相关推荐
代码之光_198016 分钟前
保障性住房管理:SpringBoot技术优势分析
java·spring boot·后端
ajsbxi21 分钟前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
颜淡慕潇1 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
尘浮生2 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea
尚学教辅学习资料2 小时前
基于SpringBoot的医药管理系统+LW示例参考
java·spring boot·后端·java毕业设计·医药管理
monkey_meng3 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马3 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng3 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
paopaokaka_luck8 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
码农小旋风9 小时前
详解K8S--声明式API
后端