通过 Spring RestTemplate 向客户端执行后续请求时会话关闭错误

Session closed error when performing subsequence requests to client via Spring RestTemplate

我正在尝试使用 spring 休息模板来执行 post 登录请求。

RestTemplate restTemplate = new RestTemplate();

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

LinkedMultiValueMap<String, Object> mvm = new LinkedMultiValueMap<String, Object>();
mvm.add("LoginForm_Login", "login");
mvm.add("LoginForm_Password", "password");

ResponseEntity<String> result = restTemplate.exchange(uriDWLogin, HttpMethod.POST, requestEntity, String.class);

一切顺利,但是当我尝试发送第二个请求时,它会生成一条错误消息:

Business Manager closes your session after 15 minutes

我该怎么做才能解决这个问题?!

当您在第一个请求中收到响应时,您应该存储通过 cookie 收到的 session id。您将在 set-cookie 响应 header 中检索它,您可以通过以下方式获取它:

//first request
RestTemplate template = new RestTemplate();
ResponseEntity<String> forEntity = template.getForEntity("http://google.bg", String.class);
forEntity.getHeaders().get("Set-Cookie").stream().forEach(System.out::println);

然后在每个后续请求中,您应该使用第一个请求中收到的值设置 Cookie 请求 header:

//subsequent request
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Cookie",cookies.stream().collect(Collectors.joining(";")));
HttpEntity<String> entity = new HttpEntity<String>(headers);
restTemplate.exchange("http://url", HttpMethod.POST, entity, String.class);

我有一个 StaticRestTemplate class,这样我就得到了相同的 RestTemplate 实例。

public class StaticRestTemplate {

    public volatile static RestTemplate rest = new RestTemplate();
 public static volatile String jsessionid = "";    
// This way, I can test on local or server just  by changing one URL.
public static volatile String baseURL = "http://192.168.178.60:8080/";
}

登录码:

   public static RestTemplate rest = new RestTemplate();
  rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
            StaticRestTemplate.jsessionid = rest.execute(StaticRestTemplate.baseURL+"j_spring_security_check", HttpMethod.POST,
                    new RequestCallback() {
                        @Override
                        public void doWithRequest(ClientHttpRequest request) throws IOException {
                            request.getBody().write(("j_username=" + email + "&j_password=" + password).getBytes());
                        }
                    }, new ResponseExtractor<String>() {
                        @Override
                        public String extractData(ClientHttpResponse response) throws IOException {
                            List<String> cookies = response.getHeaders().get("Cookie");
                            if (cookies == null) {
                                cookies = response.getHeaders().get("Set-Cookie");
                            }
                            String cookie = cookies.get(cookies.size() - 1);
                            int start = cookie.indexOf('=');
                            int end = cookie.indexOf(';');

                            return cookie.substring(start + 1, end);
                        }
                    });
            return null;

        }

现在,我的JsessionID就保存下来了,以后的请求我可以这样直接使用:

rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
            HttpHeaders requestHeaders = new HttpHeaders();
// This is where I add the cookie value
            requestHeaders.add("Cookie", "JSESSIONID=" + StaticRestTemplate.jsessionid);
            HttpEntity<String> requestEntity = new HttpEntity<>(requestHeaders);

            HttpEntity<String> rssResponse = rest.exchange(
                    StaticRestTemplate.baseURL+"dashboard",
                    HttpMethod.GET,
                    requestEntity,
                    String.class);
            StaticRestTemplate.replyString = rssResponse.getBody();
            return StaticRestTemplate.replyString;

如有疑问,请告诉我。

您可以尝试为您的 RestTemplate 禁用工厂的 cookie 管理:

HttpClient httpClient = HttpClientBuilder.create()
                    .disableCookieManagement()
                    .useSystemProperties()
                    .build();
    factory.setHttpClient(httpClient);