启用setChunkedStreamingMode后无法读取HttpURLConnection响应码求助
分块上传时HttpsURLConnection无法获取错误响应码的解决方案
你遇到的问题是分块传输场景下的典型服务端提前终止连接异常:当服务器返回403这类错误码时,会直接关闭连接,而客户端还在持续写入分块数据,后续尝试读取响应时,连接已被重置,因此抛出SocketException。去掉setChunkedStreamingMode后,HttpsURLConnection会把整个文件加载到内存再发送,虽能完整获取响应,但大文件会触发OOM。
问题根源
代码中直接忽略了输出流的IOException,导致服务器断开连接时客户端无法感知,仍继续尝试写入数据,最终连接彻底被重置,后续读取响应的操作必然失败。另外分块传输时,服务器可能在接收部分数据后就返回错误并关闭连接,不会等待客户端写完所有数据。
解决方案
调整代码逻辑,不再忽略输出流异常,在写入数据时捕获异常并及时读取服务器的错误响应;同时读取响应时优先尝试获取错误流,避免直接调用getResponseCode抛出异常。
修改后的代码示例:
private void uploadTest(File src) { int responseCode = -1; HttpsURLConnection connection = null; try { URL url = new URL("https://localhost:42019/upload"); connection = (HttpsURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.addRequestProperty("filename", "uploadedFile.txt"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setDoOutput(true); connection.setChunkedStreamingMode(2048); try (FileInputStream fis = new FileInputStream(src); BufferedOutputStream bos = new BufferedOutputStream(connection.getOutputStream())) { byte[] buffer = new byte[2048]; int count; while ((count = fis.read(buffer)) != -1) { bos.write(buffer, 0, count); bos.flush(); // 分块传输建议每块写完就flush,避免缓冲导致分块不及时 } } catch (IOException e) { // 写入时异常大概率是服务器已关闭连接,此时尝试读取响应 responseCode = getResponseCodeSafely(connection); if (responseCode != -1) { readResponse(connection, responseCode); } } // 写入无异常时正常读取响应 if (responseCode == -1) { responseCode = getResponseCodeSafely(connection); readResponse(connection, responseCode); } } catch (IOException e) { e.printStackTrace(); } finally { if (connection != null) { connection.disconnect(); } } } // 安全获取响应码的工具方法 private int getResponseCodeSafely(HttpsURLConnection connection) { try { return connection.getResponseCode(); } catch (IOException e) { // 尝试通过错误流触发响应头解析,间接获取响应码 try { if (connection.getErrorStream() != null) { return connection.getResponseCode(); } } catch (IOException ex) { ex.printStackTrace(); } return -1; } } // 读取响应的方法(替换原readRCode) private void readResponse(HttpsURLConnection connection, int responseCode) throws IOException { if (responseCode >= 200 && responseCode < 300) { // 正常响应读取输入流 try (InputStream is = connection.getInputStream()) { // 处理正常响应数据 } } else { // 错误响应读取错误流 try (InputStream es = connection.getErrorStream()) { // 处理错误响应数据 } } }
关键调整说明
- 不忽略输出流异常:写入数据时抛出IOException,说明服务器已断开连接,此时立即尝试读取响应码,服务器的响应头已发送,大概率能获取正确错误码。
- 安全获取响应码:封装
getResponseCodeSafely方法,直接调用getResponseCode抛异常时,通过getErrorStream触发响应头解析,从而获取响应码。 - 区分流类型:根据响应码选择读取
getInputStream或getErrorStream,确保能获取完整的错误响应。 - 及时flush分块:每写入一块数据就flush,确保分块及时发送给服务器,避免服务器等待超时提前关闭连接。
这样调整后,既能保持分块传输避免OOM,又能在服务器返回错误时正确获取响应码和响应内容。
内容的提问来源于stack exchange,提问作者Mysterium57632
相关产品推荐
相关产品推荐

