[英]How to log request/response using java.net.http.HttpClient?
[英]Unreliable response from java.net.http.HttpClient call using Java 11 and Spring Boot
我正在 Spring Boot 中編寫一個后端應用程序,該應用程序從第三方調用另一個 API。
我遇到了這個特定調用的問題,它檢索了一個包含不記名令牌的令牌 object,然后我在他們的其他端點中使用它。 在調用其他端點時,檢索到的令牌有時會起作用,但大多數時候不會,從而導致未經授權的響應。
@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;
}
}
這是一個示例令牌 object:
{
"access_token": "z-bu-Pde6M2dlPiaRzd5XpTrT7ohpFQZe157HHVLfdKJWsdmKCloK7AYGEw7SLCe28tjYAxo8MZOE_3W00HEa-bqgUvcrAKfxIubAq0UGXv7jLPWbRwWzhAUCDon3kdstUrJ_OKRN2y26W6qyDBGDqlP5NRSF4unH_pD_ShmpDlSxZdYUqD0da5Y2_uO6YRs5GuWA7XhI9sPa98SxuXN_dwiDJVif418xK646fUgWR8",
"token_type": "bearer",
"expires_in": "3599"
}
使用postman檢索令牌可以正常工作,因此第三方 API 不會有問題。 我也在.NET Core 3 中實現了同樣的服務,它在那里也可以正常工作。
最讓我困惑的是,實際的 HttpClient 調用有效,我確實得到了正確的 Json,它映射到我的 TokenResponse object 就好了。 只是令牌值無效......有時。
我也嘗試過使用 RestTemplate 和 WebClient Spring 庫,但結果是一樣的。 通話有效,但檢索到的令牌無效。
起初我以為我遇到了競爭條件,因為最初我在那里有另一個 HttpClient 和另一個端點,使用來自令牌調用的響應。 所以我將其簡化為僅令牌調用,並將令牌值手動復制到 postman 請求中。 沒用。
然后我想也許我的 HttpClient 授權 header 格式不正確,但這是不正確的,因為使用 postman 請求將令牌復制到受保護的端點就表明令牌不起作用。
以及我嘗試過的其他事情:
在這一點上我很迷茫,唯一想到的是,也許 HttpClient.send() 方法可能正在以一種可能會影響內容的方式解析正文? 我對此表示懷疑,但我看不出還會發生什么。
解決方案與 cookie 有關!
令牌服務器響應正在發送 2 個set-cookie
標頭,這些標頭在 Postman 和 .NET Core 中被自動處理並設置為后續的 HTTP 請求。 第 3 方 API 位於負載均衡器后面並生成這些 session cookies。
我通過在我的main
方法中使用以下代碼實現系統范圍的CookieHandler解決了這個問題。
public static void main(String[] args) {
CookieHandler.setDefault(new CookieManager());
SpringApplication.run(Main.class, args);
}
然后像這樣構建我的 HttpClient object:
...
HttpClient client = HttpClient.newBuilder().cookieHandler(CookieHandler.getDefault()).build();
...
這樣,響應set-cookie
和請求cookie
標頭將被自動處理,並在此 HttpClient 進行的所有調用中起作用。
默認情況下,CookieHandler 是使用CookiePolicy.ACCEPT_ORIGINAL_SERVER
參數創建的。 我的理解是,這使得 cookies 僅在同一主機設置和請求時才起作用。 查看文檔以獲取有關CookiePolicy的更多選項
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.