当前位置: 首页 > 知识库问答 >
问题:

来自java的不可靠响应。网http。使用Java11和Spring Boot调用HttpClient

夹谷阳夏
2023-03-14

我正在用Spring Boot编写一个后端应用程序,它从第三方调用另一个应用程序接口。

我对这个特定的调用有一个问题,它检索一个包含承载令牌的令牌对象,然后我在它们的其他endpoint中使用它。当调用其他终结点时,检索到的令牌有时工作,但大多数情况下不工作,从而导致未经授权的响应。

@RestController
public class CotizacionController {

    Logger logger = LoggerFactory.getLogger(CotizacionController.class);

    @Value("${service.credentials.tokenServer}")
    private String tokenServer;

    @Value("${service.credentials.grantType}")
    private String grantType;

    @Value("${service.credentials.username}")
    private String username;

    @Value("${service.credentials.password}")
    private String password;

    HttpClient client = HttpClient.newHttpClient();

    @RequestMapping("/create")
    public Object Create() throws IOException, InterruptedException {

        HashMap<String, String> parameters = new HashMap<>();
        parameters.put("grant_type", grantType);
        parameters.put("username", username);
        parameters.put("password", password);

        String form = parameters.keySet().stream()
                .map(key -> key + "=" 
                                + URLEncoder.encode(parameters.get(key), 
                                                    StandardCharsets.UTF_8))
                .collect(Collectors.joining("&"));

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(tokenServer))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(BodyPublishers.ofString(form)).build();

        HttpResponse<?> response = client.send(request, BodyHandlers.ofString());

        TokenResponse result = new ObjectMapper().readValue(response
                                   .body().toString(), TokenResponse.class);

        return result;
    }

}

下面是一个示例令牌对象:

{
    "access_token": "z-bu-Pde6M2dlPiaRzd5XpTrT7ohpFQZe157HHVLfdKJWsdmKCloK7AYGEw7SLCe28tjYAxo8MZOE_3W00HEa-bqgUvcrAKfxIubAq0UGXv7jLPWbRwWzhAUCDon3kdstUrJ_OKRN2y26W6qyDBGDqlP5NRSF4unH_pD_ShmpDlSxZdYUqD0da5Y2_uO6YRs5GuWA7XhI9sPa98SxuXN_dwiDJVif418xK646fUgWR8",
    "token_type": "bearer",
    "expires_in": "3599"
}

使用postman检索令牌工作得非常好,因此第三方API不会有问题。我在中也实现了相同的服务。NET核心3,它在那里也工作得很好。

最让我困惑的是,实际的HttpClient调用是有效的,我确实得到了一个正确的Json,它映射到了我的TokenResponse对象。只是令牌值无效。。。有时

我还尝试使用了RestTemboard和WebClient Spring库,但结果是相同的。调用工作,但检索令牌无效。

起初,我认为我有一个竞争条件,因为最初我有另一个HttpClient在那里,另一个endpoint使用令牌调用的响应。因此,我将其简化为只调用令牌,并将令牌值手动复制到邮递员请求中。没有工作。

然后我想也许我的HttpClient授权头格式错误,但这是不被证明的,因为简单地使用邮递员请求将令牌复制到受保护的endpoint显示令牌不起作用。

还有我尝试过的其他事情:

  • 将我在控制器中生成的表单字符串粘贴到Postman请求中以确保其有效

在这一点上,我很迷茫,唯一想到的是,也许HttpClient.send()方法可能会以可能影响内容的方式解析主体?我对此表示怀疑,但我看不出还会发生什么。

共有1个答案

韦寒
2023-03-14

解决方案与cookies有关!

令牌服务器响应发送2set-cookie标头,其中在Postman和.NET Core被自动处理并设置为后续的HTTP请求。第三方API支持负载均衡器并生成这些会话cookie。

我在main方法中使用以下代码实现了一个系统范围的CookieHandler,从而解决了这个问题。

public static void main(String[] args) {
        CookieHandler.setDefault(new CookieManager());

        SpringApplication.run(Main.class, args);
    }

然后像这样构建我的HttpClient对象:

...
HttpClient client = HttpClient.newBuilder().cookieHandler(CookieHandler.getDefault()).build();
...

这样,响应set-cookie和请求cookie标头将被自动处理,并在该HttpClient进行的所有调用中工作。

默认情况下,CookieHandler是使用CookiePolicy创建的。接受原始服务器参数。我的理解是,只有在同一主机设置并请求cookie时,cookie才能工作。有关CookiePolicy的更多选项,请查看文档

 类似资料:
  • 我尝试通过Java执行一个SOAP请求并获得SOAP响应,然后从JSP页面调用它。我研究了许多网站,尝试了许多方法,但似乎无法让它工作。 我使用一些wsdl来测试http://www.webservicex.net/australianpostcode.asmx?wsdl 我一直收到这个错误 java.io.ioException:服务器返回HTTP响应代码:500的URL:HTTP://www.

  • 对于反应式编程和SpringWebClient来说,这是一个相当新的概念,所以我正在尝试了解它,本质上,我有一个分页的结果列表,可以从一个REST服务中使用,该服务使用一个链接响应头进行响应,该响应头带有一个与下一页结果(如果存在)相关的URI。我想把所有的页面都收集到一个通量中。默认情况下,生成的ApicClient具有如下内容 那么,我是否需要对结果的每一页进行某种递归调用,将每一页合并成一个

  • 事情是这样的: 我正在为我的论文创建一个完全定制的服务器。在客户端,我希望能够请求服务器处理的数据库调用。然后,它以HTTP给出响应,以JSON提供查询结果。 我现在调用的方式是:使用JQuery的“getJSON()”方法。 虚拟示例: 在浏览器中运行带有此脚本的网页会在服务器端生成以下HTTP标头: 我的问题是:为了从浏览器上javascript的“result”参数中的响应中获得JSON负载

  • 我需要使用Spring MVC重定向到一个外部服务,使用一个带有构建的对象的POST。 HttpClientHelper.java 我可以看到目标服务正被POST请求成功命中,我需要从MCV控制器读取响应的输出作为返回值,因为它当前只返回一个404。

  • 在我的项目中,我创建了一个py函数,用于检查和修改我的谷歌日历,如下所示: 当我在lambda上测试它时,一切都完成了,但是当我从lambda创建API时: 并对其进行测试,结果是: 2017年12月20日星期三13:35:58 UTC:由于配置错误,执行失败:Lambda代理响应格式错误2017年12月20日星期三13:35:58 UTC:方法已完成,状态为:502 提前谢谢

  • 问题内容: 我的网络服务返回一个JSON对象,如下所示 即,当我将此地址放入chrome浏览器中时,我可以到达上面。 我正在尝试在浏览器中阅读此内容,以便可以创建一个下拉选项…但是从以下代码开始我一无所获: 我总是在警报框中。我用fiddler2再次检查了Web服务请求/响应是否正常,我什至可以拦截Web服务和浏览器之间的json对象。 我也试过 我又得到了空。 我已经看过Ajax要求的json响