[英]Shoud the Spring request mapping logic map to a handler method based upon the value of servletPath?
如果之前有人問過這個問題,我們深表歉意。 我在 StackOverflow 上搜索了 Spring 文檔,一般搜索了 Web,但沒有找到答案。
我是 Spring 的新手,在調查我遇到的請求映射問題的過程中,我遇到了一些不尋常和意外的(對我來說)行為,這些行為導致調用單個<url-pattern>
和@RequestMapping
來自 2 個不同的 URL。 我敢肯定這是由於我缺乏理解,所以我希望有人可以確認它應該如何表現,並且最好指出它的記錄位置。 我通過獨立的 Servlet 容器而不是 SpringBoot 使用 Spring 框架。
以下示例說明了該行為。
考慮以下 web.xml 片段
<servlet>
<servlet-name>TestSpringServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/test-spring-servlet-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>TestSpringServlet</servlet-name>
<url-pattern>/test-servlet/*</url-pattern>
</servlet-mapping>
部署在以下上下文路徑中:
/apps
test-spring-servlet-config.xml 包含:
<beans>
<mvc:annotation-driven />
<bean id="TestController" class="org.example.TestSpringServletController" />
</beans>
TestSpringServletController class 定義為:
@Controller
public class TestSpringServletController
{
@GetMapping("/test-servlet")
public void testAll(HttpServletRequest request, HttpServletResponse response) throws IOException
{
response.getWriter().append("<h2>Spring Test Servlet - testAll()</h2>");
response.getWriter().append("ContextPath: [").append(request.getContextPath()).append("]<br/>");
response.getWriter().append("ServletPath: [").append(request.getServletPath()).append("]<br/>");
response.getWriter().append("PathInfo: [").append(request.getPathInfo()).append("]");
}
@GetMapping("/test-servlet/{id}")
public void testWithId(HttpServletRequest request, HttpServletResponse response, @PathVariable String id) throws IOException
{
response.getWriter().append("<h2>Spring Test Servlet - testWithId()</h2>");
response.getWriter().append("ContextPath: [").append(request.getContextPath()).append("]<br/>");
response.getWriter().append("ServletPath: [").append(request.getServletPath()).append("]<br/>");
response.getWriter().append("PathInfo: [").append(request.getPathInfo()).append("]");
}
}
訪問: http://localhost:8084/apps/test-servlet/test-servlet
結果:
Spring Test Servlet - testAll()
ContextPath: [/apps]
ServletPath: [/test-servlet]
PathInfo: [/test-servlet]
不出所料。
訪問:
http://localhost:8084/apps/test-servlet/test-servlet/myid
結果:
Spring Test Servlet - testWithId()
ContextPath: [/apps]
ServletPath: [/test-servlet]
PathInfo: [/test-servlet/myid]
也符合預期。
但是,訪問: http://localhost:8084/apps/test-servlet
結果:
Spring Test Servlet - testAll()
ContextPath: [/apps]
ServletPath: [/test-servlet]
PathInfo: [null]
這不是我所期望的,我找不到記錄這種行為的信息。 我希望出現 404 Not Found 錯誤。 我假設正在發生的是,當 PathInfo 為 null 時,Spring 請求映射器正在使用 ServletPath。 但是,當 PathInfo 不是 null 時,則僅使用 PathInfo 值,如以下所示: http://localhost:8084/apps/test-servlet/myid
結果:
HTTP ERROR 404
Problem accessing /apps/test-servlet/myid. Reason: Not Found
我實際上確定我已經在某處讀到 servlet 不應將 servletPath 作為請求的一部分使用,但目前找不到該特定參考。
將 @GetMapping 更改為“/”用於 testAll() 和“/{id}”用於 testWithId() 也沒有達到預期的效果,因為訪問: http://localhost:8084/apps/test-servlet
現在結果在對 testWithId() 而不是 testAll() 的調用中,它現在需要尾隨 / 在它的 URL 中,以便 function 像以前一樣沒有尾隨 /。 老實說,這也不是我所預料的,並且看起來是另一種情況,其中 Spring 請求映射器使用 servletPath 代替 PathInfo(即沒有尾隨空格的 null)。 如果有人能闡明這一點,我也將不勝感激。
我發現避免此問題的一種方法是更改 url-pattern(並因此更改 servletPath)或更改 PathInfo 以使值不同。 這似乎是一個奇怪的約束(並且將部署時配置與編譯時配置緊密結合)而且我在任何地方都沒有看到。
任何人都可以提供有關這些行為的任何信息或指示,我們將不勝感激。 為這么冗長的問題道歉!
問候
====
快速更新以響應以下初始評論:
將 web.xml 替換為:
public class WebAppBootstrap implements WebApplicationInitializer
{
private static final String URI_TEST_SERVICE = "/test-servlet/*";
private static final String NAME_TEST_SERVICE = "TestSpringServlet";
@Override
public void onStartup(ServletContext servletContext) throws ServletException
{
AnnotationConfigWebApplicationContext testServletContext = new AnnotationConfigWebApplicationContext();
testServletContext.register(TestServletConfig.class);
ServletRegistration.Dynamic testDispatcher = servletContext.addServlet(NAME_TEST_SERVICE, new DispatcherServlet(testServletContext));
testDispatcher.setLoadOnStartup(1);
testDispatcher.addMapping(URI_TEST_SERVICE);
}
}
和test-spring-servlet-config.xml
與:
@Configuration
@EnableWebMvc
public class TestServletConfig
{
@Bean
public TestSpringServletController testController()
{
return new TestSpringServletController();
}
}
對觀察到的行為沒有任何影響。
查看 Spring 源代碼后,上面的行為似乎是設計使然的(盡管上面的特定用例可能不是)。
在執行查找匹配處理程序方法時確定要使用的路徑時,將調用: UrlPathHelper.getLookupPathForRequest(HttpServletRequest request)
此方法首先檢查alwaysUseFullPath
是否設置為true
。 如果是,則它使用 servlet 路徑和路徑信息作為查找路徑。
如果alwaysUseFullPath
設置為false
,那么它會嘗試僅使用路徑信息(正如您所期望的那樣)來構建查找路徑。 但是,如果找到的路徑是一個空字符串,那么它會回退到同時使用 servlet 路徑和路徑信息,即就好像alwaysUseFullPath
被設置為true
一樣。
因此,結果是 URI 的/apps/test-servlet/test-servlet
和/apps/test-servlet
都會導致查找路徑/test-servlet
,因此兩者都與testAll()
的@GetMapping
值相匹配.
遺憾的是沒有neverUseFullPath
設置,因為我不認為我觀察到的行為是可取的,即使它可能不太可能(盡管如果不同的團隊負責編寫 servlet 和部署 servlet 那么也許你可以在 URI 中得到重復項)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.