HttpURLConnection请求失败,OkHttpClient可正常返回200状态码
我之前也碰到过一模一样的情况,HttpURLConnection因为默认行为和OkHttpClient有不少差异,很容易踩坑。咱们对照你提供的OkHttpClient代码,一步步调整HttpURLConnection的实现,应该就能解决问题:
核心差异与修复点
HttpURLConnection不像OkHttpClient那样封装得那么友好,很多细节需要手动配置,以下是你必须注意的几个点:
手动指定POST请求方法
HttpURLConnection默认是GET请求,你必须显式设置setRequestMethod("POST"),否则服务器会把你的请求当成GET处理,直接返回错误。开启输出流权限
发送POST请求时,需要调用conn.setDoOutput(true),这样才能获取输出流写入请求体(哪怕是空的请求体)。完整复制请求头
确保所有OkHttpClient里的请求头都用setRequestProperty逐个添加到HttpURLConnection中,尤其是Jenkins-Crumb和Authorization这两个关键头,Jenkins对这两个头的校验很严格。处理空的FormBody
你在OkHttpClient里用了new FormBody.Builder().build()(空表单),对应到HttpURLConnection里,需要获取输出流并写入空内容(哪怕只是一个空字节数组),因为有些服务器会校验请求体的存在性。
完整的HttpURLConnection实现代码
照着这个代码写,应该就能得到和OkHttpClient一样的200响应:
import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; public class JenkinsRequestTest { public static void main(String[] args) throws Exception { // 目标URL URL targetUrl = new URL("http://some.cz/url"); HttpURLConnection conn = (HttpURLConnection) targetUrl.openConnection(); // 1. 设置POST请求方法 conn.setRequestMethod("POST"); // 2. 允许写入请求体 conn.setDoOutput(true); // 3. 复制所有请求头 conn.setRequestProperty("Jenkins-Crumb", "325asdfse534"); conn.setRequestProperty("Authorization", "Basic 5645762535t"); conn.setRequestProperty("Cache-Control", "no-cache"); conn.setRequestProperty("Postman-Token", "563b8065-87b0-47a4-b9af-eaaeaaab4bb0"); // 4. 写入空的请求体(对应OkHttpClient的空FormBody) try (OutputStream outputStream = conn.getOutputStream()) { outputStream.write(new byte[0]); // 空内容,确保请求体存在 } // 获取响应码 int responseCode = conn.getResponseCode(); System.out.println("response.code() = " + responseCode); // 关闭连接释放资源 conn.disconnect(); } }
额外排查技巧
如果还是返回非200状态码,建议你添加错误流读取逻辑,看看服务器返回的具体错误信息,比如crumb是否过期、Authorization是否正确:
if (responseCode != HttpURLConnection.HTTP_OK) { try (BufferedReader errorReader = new BufferedReader( new InputStreamReader(conn.getErrorStream()))) { String errorLine; System.err.println("服务器错误信息:"); while ((errorLine = errorReader.readLine()) != null) { System.err.println(errorLine); } } }
另外,也可以检查是否有代理设置差异:OkHttpClient可能自动使用系统代理,而HttpURLConnection如果不需要代理,可以添加conn.setProxy(java.net.Proxy.NO_PROXY)试试。
内容的提问来源于stack exchange,提问作者Harold L. Brown

