Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 重定向视图未使用位置的相对路径_Spring_Spring Mvc_Reverse Proxy - Fatal编程技术网

Spring 重定向视图未使用位置的相对路径

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 =

我有一个web服务设置,可以从根目录(“/”)重定向到页面('my/page.html')

所以,
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