Java POST请求application/x-www-form-urlencoded获取Token遇400错误排查
解决Java调用Token API返回400错误及相关问题
看起来你的代码里有几个明显的问题导致了400错误,还有一些细节处理不当引发了额外异常,咱们一步步来梳理修正:
1. 重复操作输出流导致请求体异常
你的代码同时用了OutputStreamWriter和直接获取OutputStream来操作请求体,这会导致输出流被重复处理,请求体要么没正确发送,要么内容不完整:
OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream()); wr.write(urlParameters); // 下面这段重复操作会破坏之前的写入,导致请求体异常 OutputStream os = con.getOutputStream(); os.flush(); os.close();
正确做法是只用一种方式写入请求体,写完后统一完成flush和close操作。
2. 调试信息错误
代码里打印了Sending 'GET' request,但你明明用的是POST请求,这会误导调试;而且打印的是os(输出流对象),这毫无意义,应该打印实际请求的URL。
3. HTTPS连接配置问题
出现sun.net.www.protocol.https.DelegateHttpsURLConnection错误,通常和HTTPS证书验证有关——如果目标API用的是自签名证书,Java默认会拒绝连接,需要调整证书信任配置。
修正后的完整代码
BufferedReader in = null; String response = ""; String urlParameters = "grant_type=client_credentials"; try { URL obj = new URL("你的API实际请求URL"); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); // 设置请求方法为POST con.setRequestMethod("POST"); // 规范设置请求头(注意参数名大小写) con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); // 重点:Basic后面的value必须是 clientId:clientSecret 的Base64编码值 con.setRequestProperty("Authorization", "Basic 你的Base64编码凭证"); // 允许输出请求体 con.setDoOutput(true); // 用try-with-resources自动管理流,避免手动关闭的遗漏 try (OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream())) { wr.write(urlParameters); wr.flush(); } // 获取响应码并打印正确的调试信息 int responseCode = con.getResponseCode(); System.out.println("\nSending 'POST' request to URL : " + obj); System.out.println("Response Code: " + responseCode); // 用StringBuilder拼接响应内容,比直接String拼接更高效 StringBuilder responseBuilder = new StringBuilder(); in = new BufferedReader(new InputStreamReader(con.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { responseBuilder.append(inputLine); } response = responseBuilder.toString(); System.out.println("Response Body: " + response); } catch (IOException e) { // 关键:400错误时要读取错误流,获取API返回的具体错误信息 if (con != null) { try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(con.getErrorStream()))) { String errorLine; StringBuilder errorBuilder = new StringBuilder(); while ((errorLine = errorReader.readLine()) != null) { errorBuilder.append(errorLine); } System.err.println("API Error Response: " + errorBuilder.toString()); } catch (IOException ex) { ex.printStackTrace(); } } e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } }
额外注意事项
- Authorization头正确性:
Basic后面的value必须是client_id:client_secret的Base64编码字符串,你可以用Java自带的工具类生成:String credentials = "你的clientId:你的clientSecret"; String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); - HTTPS证书处理:如果是自签名证书,测试环境可以临时跳过验证(生产环境绝对禁用):
// 临时跳过HTTPS证书验证(仅测试用) TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {} public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {} } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HostnameVerifier allHostsValid = (hostname, session) -> true; HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); - 请求体编码:如果参数值包含特殊字符,需要用
URLEncoder.encode()对参数值单独编码,避免格式错误。
内容的提问来源于stack exchange,提问作者Kein J
相关产品推荐
相关产品推荐

