首页 > 解决方案 > Spring RestTemplate 似乎不是线程安全的 wrt 标头

问题描述

我有一个 Spring Web 客户端,它使用两个不同的基本身份验证用户发布到 Spring Web 服务器(相同的 URL)。这是一个已知问题,我不能同时使用一个RestTemplate吗?

当我使用单个RestTemplate并且请求几乎是同时的(在不同的线程中)时,尽管我在标头中指定了不同的用户,但接收服务器认为它们来自同一个用户!请注意,请求和标题(以及帖子的正文)是为每个请求新分配的。

它工作正常,当我使用单个RestTemplatesynchronized()在调用周围放置

response = RestTemplate.exchange(url, method, requestParams, MyResponse.class) 

我还尝试创建两个RestTemplate实例,每个用户一个 - (每个都用 构建RestTemplateBuilder)也可以。我会保留这个解决方案,但令我惊讶的是它是必需的。

这是一个已知的问题?

(我看到stackOverflow回答说aRestTemplate在构造后是线程安全的,但是标头是随请求传入的,而不是作为已经构造的设置RestTemplate...)

====

这是 2 个不同调用的示例,使用 2 个不同的 RestTemplates,因为有时使用相同的方法会出现问题:

public OperationStatus getOpStatus(String gufi) {
    HttpEntity<String> requestParams = new HttpEntity<>(Utils.createBasicHeader(cfg.getManager(), cfg.getManPass()));
ResponseEntity<OperationStatus> restResponse = null;
try {
        restResponse = managerRestTemplate.exchange(
            cfg.getNussOpApiPath(),  HttpMethod.GET,  requestParams,  OperationStatus.class);
    } catch (RestClientException e) {
    ...
    }
    OperationStatus opState = restResponse.getBody();
    opState.setHttpStatusCode(String.valueOf(restResponse.getStatusCodeValue()));                                                                
    return opState;
}

这里有个发帖的方法,使用优先级切换rest模板(当时目标服务器是通过用户的权限来识别优先级的)

UTMRestResponse doPost(Object objToSend, String url, String msg) throws IOException {

    String user = cfg.getOpUser();
    String pass = cfg.getOpPass();
    RestTemplate restTemplate = opUserRestTemplate;
    boolean isPriorityOp = false;

    if ( objToSend instanceof OpPost) {
        OpPost post = (OpPost) objToSend;
        String flightNum = post.getFlightNumber();
        isPriorityOp = Boolean.TRUE.equals(post.getPriorityOp());  // null is false                                                                             
    } else if ( objToSend instanceof PositionPost) {
        PositionPost post = (PositionPost) objToSend;
        isPriorityOp = Boolean.TRUE.equals(post.getPriorityOp());  // null is false                                                                             
    }

    if (isPriorityOp) {
        user = cfg.getUserEmergency();
        pass = cfg.getPassEmergency();
        restTemplate = emergRestTemplate;
    }

    String jsonToSend = CommonsObjectMapper.get().writeValueAsString(objToSend);
    HttpEntity<String> requestParams = new HttpEntity<>(jsonToSend, Utils.createBasicHeader(user, pass));

    UTMRestResponse restResponse = restTemplate.exchange(
            url, HttpMethod.POST, requestParams, UTMRestResponse.class).getBody();
    if (restResponse.getHttpStatusCode().startsWith("4")) {
        String fmt = "Status:{}, url:{}, jsonSent:{}, response:{}";
        logger.error(fmt, restResponse.getHttpStatusCode(), url, jsonToSend, restResponse.getMsg());
    }
    return restResponse;
}

标签: springspring-bootthread-safetyresttemplate

解决方案


推荐阅读