servlet(容器?规范?实现?)为啥会在 url 路径这个问题上设计的如此古怪?

2017-05-16 20:05:35 +08:00
 abcbuzhiming
我是最近才注意到这一点,其他有 http 实现的语言(框架),基本上,在 http 地址解析这个问题上,会倾向于把域名根路径“/”之后开始的部分视为一个整体,嗯,最多就是可能会把路径的最后部分——如果有后缀名的话——视为文件本身。比如 http://www.v2ex.com/aaa/bbb/ccc/ddd/123.txt。那么请求路径就是 /aaa/bbb/ccc/ddd/。这是一个整体,一般不会再拆分。但是在 servlet 的实现上,有两个东西,1 个叫 servletPath ( request.getServletPath()),一个叫 pathinfo ( request.getPathInfo())。而且很有意思的是,这两个东西的值是和 web.xml 配置文件中的 url-pattern 所采用的模式有关,我想了很长时间,没想明白这样的意义在哪里,为啥 servlet 在设计上没有把 /aaa/bbb/ccc/ddd/视为一个整体,而专门搞了 ServletPath,PathInfo。这应该是有某种作用的
3390 次点击
所在节点    Java
12 条回复
sagaxu
2017-05-16 20:34:33 +08:00
因为一个 webserver 上要跑多个 webapps 啊,/app1/path,/app2/path,...
abcbuzhiming
2017-05-16 21:19:29 +08:00
@sagaxu 然而你说的这个 app 其实指的是 ContextPath

http://blog.csdn.net/cooljia/article/details/187882
你可以看这篇文章,说的很详细,
Context Path + servlet path + path info = request uri
这里的关键就是为啥会分 servlet path 和 path info。把 Context Path 单独列出来是可以理解的,作为隔离应用的措施,但是后两者是干嘛的呢
echo1937
2017-05-16 21:32:34 +08:00
这个问题我在学习 Servlet 时也发现了,当时有类似想法,但没有深究。
cheneydog
2017-05-16 21:50:11 +08:00
区分 api 请求和静态文件请求的一种方式。
SoloCompany
2017-05-16 23:11:16 +08:00
有什么问题吗?
REQUEST_URI = /a/b/c.php/d/e/f?x=1
SCRIPT_NAME = /a/b/c.php
PATH_INFO = /d/e
_GET = [ “ x ” => 1 ]

是什么让你会觉得这是 java 发明的?
abcbuzhiming
2017-05-17 08:57:17 +08:00
@cheneydog 如何个区分法,说明白一点,我专门去研究了 tomcat 对静态文件的默认处理,发现它默认是通过“/”这个路径映射的 servlet 处理的,此时整个静态文件地址都是 servletPath,pathinfo 为空了。如果按 servletPath 存在就按 api 请求理解的话,好像没有 servletpath 不存在的时候
abcbuzhiming
2017-05-17 09:01:23 +08:00
@SoloCompany 你这有点强词夺理了,你提的 php 中的这个 pathinfo 是 CGI 中的标准,它最初的含义指的是描述你所调用的这个 php 文件在服务器上的真实位置。然而后来大部分 php 框架利用这点,把它当成了地址映射。CGI 和 servlet 是一回事吗? servlet 里的这个 pathinfo 可不是出现在 jsp 后面的,你要能证明 CGI 中的这个 pathinfo 和 servlet 存在渊源或者有原理设计上的类似,请给出证据
SoloCompany
2017-05-17 09:25:58 +08:00
@abcbuzhiming #7 我用得着去证明吗?是不是一回事你自己不会判断?就你这语气本来不想再回复了,算是知道什么叫做永远叫不醒一个自以为是的人。这是最后一条回复,你自己爱怎么理解就怎么理解吧

<servlet>
<servlet-name>c.jsp</servlet-name>
<jsp-file>/a/b/c.jsp</jsp-file>
</servlet>

<servlet-mapping>
<servlet-name>c.jsp</servlet-name>
<url-pattern>/a/b/c.jsp/*</url-pattern>
</servlet-mapping>

自己去看一下早期 jsp 引擎是怎么实现的
以及后来 jsp 的默认 mapping 怎么又被规范为了 *.jsp, 而规范不支持 *.jsp/* 这种类型的 mapping 只能通过手工加入
abcbuzhiming
2017-05-17 21:57:42 +08:00
@SoloCompany 首先,我为我的语气道歉,你是对的,我找了一圈,pathinfo 就是对应的 CGI 变量 pathinfo。这一点在 orcale 的文档里有描述,虽然我还是没找到这样设计的理由。貌似有点吸引早期的 CGI 程序的开发者的意思。另外你说的最后一句话,早期 jsp 引擎实现和后来被规范成*.jsp,我没有找到相关的资料,请不吝赐教
SoloCompany
2017-05-17 23:34:35 +08:00
@abcbuzhiming 早期 jsp 引擎的实现和 php 是比较类似的,就是类似 *.jsp/* 都会被 jsp 引擎处理,只要路径中包含 jsp (并且文件存在),就会被映射
但是会存在歧义
比如 /1.jsp/2.jsp/3 并且这两个路径下的 jsp 文件都存在
那应该是映射为 servletPath=/1.jsp, pathInfo=/2.jsp/3 呢
还是 servletPath=/1.jsp/2.jsp, path=/3
完全依赖引擎的实现, Servlet 规范里面并没有这种定义的支持.

Servlet 规范的 mapping 只支持一个 *,即要么按文件名后缀 map ( pathInfo 永远是 null) 要么按前缀来 map, 而且必须是 ‘/*’ (/* 代表的就是 pathInfo)

默认的 jsp servlet mapping 的定义是写在 CATALINA_BASE/web.xml 里面, 就是 *.jsp, 通过这个 mapping 的请求也一定没有 path info

默认配置还有一个 DefaultServlet, 用来服务静态文件

至于 tomcat 的 jsp 引擎什么时候变更为和规范一致,我已经不记得了,只记得很早的时候是可以 (带 path) 的,后来就不可以了,也很可能是 tomcat 一直都默认不可以带 path 而是其它引擎( resin / jetty 之类的) 可以
搜了一下也只能找到这个帖子 http://tomcat.10.x6.nabble.com/troubleshooting-getPathInfo-in-jsp-files-td2158648.html

最后,无论是哪个语言的 HTTP 服务引擎, 所面对的概念都没有什么太大差别, 基本上都遵循 CGI 的定义,你看 javadoc 的时候没看到 request.getXXX 的说明很多都有说明是相当于 CGI 的哪个环境变量吗?
abcbuzhiming
2017-05-17 23:39:37 +08:00
@SoloCompany 最后那段话的意思,是不是可以说现有的 Http 服务器的技术源头,或者说鼻祖都来源于 CGI ?都受到 CGI 的历史影响?那这个地球上有没有完全和 CGI 无关的 Http 服务器实现啊?
SoloCompany
2017-05-17 23:47:33 +08:00
@abcbuzhiming 我不觉得这算是什么技术源头吧,因为 CGI 是最早的服务器编程方式,所有人都熟悉,专家也熟悉,制订标准的时候肯定也会参考,但同时也会做一些修改,比如 CGI 的 SCRIPT_NAME 环境变量在 Servlet 里面就改名为了 ServletPath, javadoc 里面都相关映射的说明

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/361773

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX