簡體   English   中英

Spring 請求映射邏輯 map 是否應該基於 servletPath 的值到處理程序方法?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM