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代码。这种设计模式被称为装饰器模式。
- 请求参数的处理和修改: 你可以通过扩展
HttpServletRequestWrapper
来拦截请求参数,修改参数的值或者进行额外的验证操作。- URL的修改和重定向: 借助
HttpServletRequestWrapper
,你可以修改请求的URL,进行重定向操作,或者对URL进行特定规则的处理。- 请求头的定制: 如果需要向请求头中添加自定义的信息,或者根据请求头来做特定的处理,
HttpServletRequestWrapper
也是一个合适的选择。- 请求内容的修改: 当需要对请求的内容进行加密、解密、压缩或其他变换时,也可以通过包装请求来实现这些需求。
typescriptimport 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并不能快速的帮我解决这个问题。因为,学习并不总是瞬间见效的,它可能不会立即展现出明显的提升。然而,学习为我们打下了解决问题的基础,使得我们在遇到问题和解决问题的过程中得以游刃有余,融会贯通。
因此我明白,知识不仅是为了应付眼前,更是为了提升透视未来的能力,让我们在挑战面前能够自信从容。每一次的学习对我们来说并不都是受益匪浅的,但是我们的成长铺就了一条通往更高境界的道路。