从request请求可以获取URL、URI、ServletPath、ContextPath、RealPath,它们之间有何区别?Let’s go!
可能的误区
以SpringBoot配置为例,spring.application.name
表示这个Spring应用叫什么,并不代表这个web应用叫什么,决定web应用叫什么的是server.servlet.context-path
,也就是我们常说的应用名或者应用前缀或web容器上下文路径。下面这个配置访问应用的所有地址都是以 http://ip:8080/demo 开头,而不是 http://ip:8080/myapp ;而Spring应用名称spring.application.name
应用之一便是在SpringCloud微服务框架下服务的标识。
1 | spring.application.name=myapp # Spring应用名称 |
实操验证
以SpringBoot环境为例,本地部署,有如下配置:
application. properties
1 | spring.application.name=myapp |
一个控制层
1 |
|
结果如下:
描述 | 值 |
---|---|
application. properties | server.servlet.context-path=/demo |
访问链接 | http://127.0.0.1:8080/demo/test?name=zs |
URL | http://127.0.0.1:8080/demo/test |
URI | /demo/test |
ServletPath | /test |
ContextPath | /demo |
RealPath | C:\Users\WS\AppData\Local\Temp\tomcat-docbase.6884443025746620464.8082\ |
结合表格结果,加入官方术语简单直白的总结一波:
URL:即 Uniform Resource Locator(统一资源定位符),资源在网络中的唯一的地址,格式:协议+主机+端口+路径
URI:即 Uniform Resource Identifier(统一资源标识符),用于标识某一互联网资源名称的字符串,格式:路径
ServletPath:Servlet路径,简单理解为web应用提供资源的路径,其表现之一在SpringMVC中就是控制层的一个完整资源路径
ContextPath:web应用的上下文路径,简单理解为web容器最开始路径,所有的web资源(路径)都要挂在它的下面
RealPath:真实路径,简单理解为web资源在服务器的真实物理路径,
.HttpServletRequest#getRealPath(String)
的方法返回的是web容器所在的真实物理地址(也就是根目录)加上该方法的参数的值的结果,说白了算是字符串拼接,没有验证资源是不是存在。使用场景笔者并不是太了解,可能在某个静态资源定位上比较有用吧,在 Servlet 2.1之后该方法已经过期,替代者如下
ContextPath斜杠“/”问题
现在我们知道application. properties 中server.servlet.context-path
配置的 “/demo” 就是 ContextPath的值了,发散一下,如果我们不配置,那ContextPath的值是多少呢?答案是空字符串(长度为0),如果配置了“/”或“/demo/”或“//”呢?结果分别是空字符串和“/demo”和启动异常,话不多说直接看源码,进对应配置类 org.springframework.boot.autoconfigure.web.ServerProperties
1 | public class ServerProperties { |
虽然该配置类是SpringBoot下的,我们知道SpringBoot内置tomcat,故而对外提供web容器(tomcat)的配置,最后转换成web容器对应的配置,所以这个配置类的参数规范肯定是要符合tomcat的要求的。
通过源码不难看出,SpringBoot对server.servlet.context-path
进行了处理:
- 两边去空格
- 包含有效字符串的情况下,去除末尾的“/”字符
所以配置“/”或“/demo/”的结果也就解释得通了,而配置两个斜杠“//”的情况下,上述代码得到的结果为“/”,这个配置扔到tomcat肯定是报错了,这也就反映出为什么我们在写@RequestMapping
的时候要以“/”开头了,除了协议与主机名之间的分隔之外,一个url不应该以双斜杠“//”出现,大多数情况下多斜杠的url是被允许的,它们只会被当做一个斜杠处理,这是web容器对我们的“宽容”,但开发者不应该乱写,更不能只知其表不知其里。