我有一个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;
}
我期望重定向响应将其location
标头设置为相对路径:/my/page.html
。但是,实际上,它设置为完整路径:http://localhost/my/page.html
。
这引起了一些问题,因为此应用程序运行在Docker容器中,该容器认为它正在为端口80提供服务;您可能已经注意到完整路径在URL中删除了:8080
端口说明符。 Docker容器在反向代理后面运行,该反向代理将对8080
的请求映射到该容器。如果location
标头是相对的并设置为/my/page.html
,则预期浏览器客户端将使用正确的主机名(localhost:8080
),因此反向代理会将其重定向到正确的主机名。页面。
从代码中可以看到,我尝试将ContextRelative
对象中的RedirectView
选项设置为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
完成上述操作的方法,我很乐意接受该解决方案。
答案 0 :(得分:1)
您的代码的行为是正确的,因为您是说您的redirectview URL在上下文中是相对的,但是它是有效的url,因此spring将其构建为url,而/my/page.html却不是有效的网址。说的问题是,您应该以全双工方式配置url重写并在反向代理中解决问题,实际上对于代码(前提是该代码是否在运行于80端口的服务器上运行),该代码将映射您的url在80上,否则您应该手动输入网址,如下所示:
@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 Header时,它是纯字符串,请勿从servlet环境中传递。重定向发生在您的浏览器中,在这种情况下,该重定向获取了一个相对URL,因为在控制器中您设置了纯字符串,并且浏览器已经知道已经代理的服务器。
更新2 RedirectView类的核心逻辑是一个受保护的方法,称为sendRedirect(...)。
/**
* Send a redirect back to the HTTP client
* @param request current HTTP request (allows for reacting to request method)
* @param response current HTTP response (for sending response headers)
* @param targetUrl the target URL to redirect to
* @param http10Compatible whether to stay compatible with HTTP 1.0 clients
* @throws IOException if thrown by response methods
*/
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response,
String targetUrl, boolean http10Compatible) throws IOException {
String encodedURL = (isRemoteHost(targetUrl) ? targetUrl : response.encodeRedirectURL(targetUrl));
if (http10Compatible) {
HttpStatus attributeStatusCode = (HttpStatus) request.getAttribute(View.RESPONSE_STATUS_ATTRIBUTE);
if (this.statusCode != null) {
response.setStatus(this.statusCode.value());
response.setHeader("Location", encodedURL);
}
else if (attributeStatusCode != null) {
response.setStatus(attributeStatusCode.value());
response.setHeader("Location", encodedURL);
}
else {
// Send status code 302 by default.
response.sendRedirect(encodedURL);
}
}
else {
HttpStatus statusCode = getHttp11StatusCode(request, response, targetUrl);
response.setStatus(statusCode.value());
response.setHeader("Location", encodedURL);
}
}
该方法首先检索url,然后如果http10Compatible为true,则最终将使用response.sendRedirect(encodedURL);否则,只需将您的相对网址放在位置标头中,而无需传递servlet api。在您的代码中,您不会提供有效的if条件来阻止Servlet api的sendRedirect的数据。这可以解释为什么在您的代码中有问题。当然,在任何其他代码分支中:http10Compatible为false,等等,您的代码只需在Location标头中放置一个字符串即可,因为在执行重定向的浏览器中会到达一个相对的URL。
对于这是否是Servlet API的错误的问题,我可以输入官方接口代码:
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;
您可以阅读评论摘录:
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
阅读它,我可以说这不是一个bug,而是servlet api的一个功能,但是,它放置了唯一知道自身的服务器主机,因此,如果使用反向代理,它将无法正常工作。
我希望这可以很好地解释问题。