Spring 重定向视图未使用位置的相对路径
我有一个web服务设置,可以从根目录(“/”)重定向到页面('my/page.html') 所以,Spring 重定向视图未使用位置的相对路径,spring,spring-mvc,reverse-proxy,Spring,Spring Mvc,Reverse Proxy,我有一个web服务设置,可以从根目录(“/”)重定向到页面('my/page.html') 所以,http://localhost:8080/应重定向到http://localhost:8080/my/page.html 代码如下: @RequestMapping(method = RequestMethod.GET, value = "/") public RedirectView localRedirect() { final RedirectView redirectView =
http://localhost:8080/
应重定向到http://localhost:8080/my/page.html
代码如下:
@RequestMapping(method = RequestMethod.GET, value = "/")
public RedirectView localRedirect()
{
final RedirectView redirectView = new RedirectView();
redirectView.setContextRelative(true);
redirectView.setUrl("/my/page.html");
return redirectView;
}
我期望重定向响应将其位置
标题设置为相对路径:/My/page.html
。但是,实际上,它被设置为完整路径:http://localhost/my/page.html
这导致了一些问题,因为此应用程序运行在Docker容器中,该容器认为它正在为端口80提供服务;您可能已经注意到,完整路径删除了URL中的:8080
端口说明符。Docker容器在反向代理后面运行,反向代理将8080
的请求映射到容器。如果位置
标题是相对的,并设置为/my/page.html
,则浏览器客户端将使用正确的主机名(localhost:8080
),因此它将被反向代理重定向到正确的页面
从我的代码中可以看到,我尝试将重定向视图
对象中的上下文相对
选项设置为true。这里还有什么我遗漏的吗
编辑
@RequestMapping(method = RequestMethod.GET, value = "/")
public void localRedirect(HttpServletResponse response) {
response.setStatus(HttpServletResponse.SC_FOUND);
response.setHeader("Location", "/my/page.html");
}
我已使用上述代码重新定向到工作。但是,我仍然很好奇,如果有人知道如何通过Spring的
RedirectView
和RedirectStrategy
实现上述目标,我很乐意接受这个解决方案。您的代码行为是正确的,因为您说您的RedirectView url在上下文上是相对的,但它必须是一个有效的url,因此spring将其构建为一个url,/my/page.html不是一个有效的url。说问题在于,您应该以全双工方式配置url重写,并在反向代理中解决问题,事实上,如果代码运行在80端口上的服务器上,则代码会将您的url映射到80,否则您应该手动编写url,如下所示:
@RequestMapping(method = RequestMethod.GET, value = "/")
public RedirectView localRedirect()
{
final RedirectView redirectView = new RedirectView();
redirectView.setUrl("http://localhost:8080/my/index.html");
redirectView.setHosts();
return redirectView;
}
我试着在我的pc上运行两个应用程序实例,一个在80上,另一个在8080上,重定向工作正常
更新:
当您使用RedirectView时,重定向将在服务器端通过HttpServletResponse.sendRedirect调用发生,当然,如果您的服务器处于反向代理之后,您的服务器端应用程序将无法知道它。
当您在控制器中使用set Location头时,它是一个普通字符串,不能从servlet环境中传递。重定向发生在浏览器中,在这种情况下接收相对url,因为在控制器中设置了一个普通字符串,并且浏览器已经知道已经代理的服务器
更新2
RedirectView类的核心逻辑是一个名为sendRedirect(…)的受保护方法
该方法首先检索url,然后如果http10Compatible为true,则最终将使用response.sendRedirect(encodedURL);否则,只需将您的相对url放在Location头中,而不传递ServletAPI。在您的代码中,您没有为阻止Servlet api的sendRedirect的活动if条件提供数据。这可以解释为什么在代码中出现问题。当然,在任何其他代码分支中:http10Compatible at false等等,您的代码只需在Location头中放入一个字符串,它就能工作,因为在您的浏览器中,执行重定向的程序会到达一个相对url
关于这是否是Servlet API的bug的问题,我可以将官方接口代码放在下面:
HttpServletResponse.java:
/**
* Sends a temporary redirect response to the client using the specified
* redirect location URL. This method can accept relative URLs; the servlet
* container must convert the relative URL to an absolute URL before sending
* the response to the client. If the location is relative without a leading
* '/' the container interprets it as relative to the current request URI.
* If the location is relative with a leading '/' the container interprets
* it as relative to the servlet container root.
* <p>
* If the response has already been committed, this method throws an
* IllegalStateException. After using this method, the response should be
* considered to be committed and should not be written to.
*
* @param location
* the redirect location URL
* @exception IOException
* If an input or output exception occurs
* @exception IllegalStateException
* If the response was committed or if a partial URL is given
* and cannot be converted into a valid URL
*/
public void sendRedirect(String location) throws IOException;
读了它,我可以说它不是一个bug,而是ServletAPI的一个特性,但是它是唯一一个知道自己的服务器主机,因此它不能与反向代理一起工作
我希望这能很好地解释这个问题。请参阅我上面的编辑。我无法指定完整的主机名。主机名必须指向反向代理,但我不希望此web服务知道它。因此,答案是RedirectView调用
HttpServletResponse.sendRedirect
,其中包括完整的主机名。您提到,sendRedirect
使用servlet环境来解释为什么包含完整的主机名。我理解得对吗?我不明白这为什么有意义。也许这需要一个单独的问题。有趣的是,我通过禁用HTTP 1.0兼容性使RedirectView正常工作,这将更改代码路径以设置位置头,而不是使用sendRedirect
。这非常有趣!但使用RedirectView的问题基本上是url是在服务器端组成的,然后位置头的构建方式取决于ServletAPI。我调试了spring代码,发现url是相对的,因此我可以说您的问题是由servletapi引起的,禁用http1兼容性可以实现这一点。使用heands编写的location头是有效的,因为location头不会通过servlet特定的redirest逻辑传递我的答案,包括官方代码片段,以解释奇怪的bheaviour
/**
* Sends a temporary redirect response to the client using the specified
* redirect location URL. This method can accept relative URLs; the servlet
* container must convert the relative URL to an absolute URL before sending
* the response to the client. If the location is relative without a leading
* '/' the container interprets it as relative to the current request URI.
* If the location is relative with a leading '/' the container interprets
* it as relative to the servlet container root.
* <p>
* If the response has already been committed, this method throws an
* IllegalStateException. After using this method, the response should be
* considered to be committed and should not be written to.
*
* @param location
* the redirect location URL
* @exception IOException
* If an input or output exception occurs
* @exception IllegalStateException
* If the response was committed or if a partial URL is given
* and cannot be converted into a valid URL
*/
public void sendRedirect(String location) throws IOException;
This method can accept relative URLs; the servlet
* container must convert the relative URL to an absolute URL before sending
* the response to the client