我正在做一个Spring项目。这是我的基本控制器:
@Controller
public class Editor {
private static final String EDITOR_URL = "/editor";
@RequestMapping(value = EDITOR_URL, method = {POST, GET})
public ModelAndView edit(HttpServletResponse response,
HttpServletRequest request,
RedirectAttributes redirectAttributes,
@RequestParam Map<String, String> allRequestParams) {
// The code is trimmed to keep it short
// It doesn't really matter where it gets the URL, it works fine
String redirectURL = getRedirectUrl();
// redirectURL is going to be /editor/pad.html
return new ModelAndView("redirect:" + redirectUrl);
}
从web . xml: <servlet-mapping>
<servlet-name>edm</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
我已经嵌入了jetty,我正在尝试集成测试:
@Test
public void redirectToEditPadSuccess() throws Exception {
HttpHeaders requestHeaders = new HttpHeaders();
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(END_POINT + "/edm/editor")
.queryParam("param1", "val1")
.queryParam("param2", "val2");
HttpEntity<?> entity = new HttpEntity<>(requestHeaders);
HttpEntity<String> response = restTemplate.exchange(
builder.build().encode().toUri(),
HttpMethod.POST,
entity,
String.class);
HttpHeaders httpResponseHeaders = response.getHeaders();
List<String> httpReponseLocationHeader = httpResponseHeaders.get("Location");
assertTrue(httpReponseLocationHeader.size() == 1);
String redirectLocation = httpReponseLocationHeader.get(0);
URL redirectURL = new URL(redirectLocation);
assertEquals("/edm/editor/pad.html", redirectURL.getPath());
}
所以当我执行上面的代码时,它工作得很好,我得到了一个绿色的OK符号。
现在,控制器接受POST和GET方法。如果我使用GET方法(代替HttpMethod)执行测试。POST与HttpMethod.GET),结果将是一个404。
日志显示:
WARN org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/edm/editor/pad.html] in DispatcherServlet with name 'edm'
我试图调试应用程序到DispatcherServlet和奇怪的事情是,与GET, 302/重定向响应后,Dispatcher被再次调用,并把它变成一个200 -不知道如何和为什么。
我将试着解释发生了什么,然后提供一个解决方案。
首先让我们忘记您正在运行一个rest用例,并假设请求来自浏览器。
场景1:浏览器发出GET请求,服务器响应重定向
在这种情况下,浏览器将响应状态码读取为302
,并使用Location
响应头发出另一个请求。用户看到快速重新加载,但没有注意到任何错误。
场景2:浏览器发出POST请求,服务器用重定向响应
在这种情况下,浏览器遵循响应代码并发出重定向,但是,第二个请求是GET请求,并且原始请求正文在第二个请求中丢失。这是因为严格按照HTTP标准,如果没有用户的明确请求,浏览器不能将数据"重新发布"到服务器。(有些浏览器会提示用户是否要重新发布)
现在在您的代码中,RestTemplate
正在使用我认为是默认的HttpClientFactory
,最有可能的是这个:https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpRequestFactory.java。
RestTemplate是这样处理上面两个场景的:
场景1:Rest模板发出GET请求,服务器用重定向响应这里Rest Template实例将完全像浏览器一样工作。这就是为什么正在发出两个请求,第二个请求正在寻找/edm/editor/pad.html
Scenario 2 : Rest Template issues a POST request, and the server responds with a redirect.
在这种情况下,Rest Template将在第一次调用后停止,因为它不能自动覆盖您的请求方法并将其更改为GET
,并且它不能像浏览器那样提示您获得许可。
解决方案:当创建RestTemplate
的实例时,将客户端工厂的重写版本传递给它,类似于
new RestTemplate(new SimpleClientHttpRequestFactory() {
protected void prepareConnection(HttpURLConnection conn, String httpMethod) throws IOException {
super.prepareConnection(conn, httpMethod);
conn.setInstanceFollowRedirects(false);
}
});
指示rest模板在第一个请求后停止。
很抱歉这么长时间的回答,但我希望这能澄清一些事情。