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

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

相关推荐
沈韶珺1 小时前
Visual Basic语言的云计算
开发语言·后端·golang
沈韶珺1 小时前
Perl语言的函数实现
开发语言·后端·golang
美味小鱼2 小时前
Rust 所有权特性详解
开发语言·后端·rust
我的K84092 小时前
Spring Boot基本项目结构
java·spring boot·后端
慕璃嫣3 小时前
Haskell语言的多线程编程
开发语言·后端·golang
晴空๓3 小时前
Spring Boot项目如何使用MyBatis实现分页查询
spring boot·后端·mybatis
Hello.Reader7 小时前
深入浅出 Rust 的强大 match 表达式
开发语言·后端·rust
customer0810 小时前
【开源免费】基于SpringBoot+Vue.JS体育馆管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
计算机-秋大田13 小时前
基于微信小程序的电子竞技信息交流平台设计与实现(LW+源码+讲解)
spring boot·后端·微信小程序·小程序·课程设计