特定设备蜂窝网络下POST JSON至EC2实例超时问题求助
以下Kotlin代码在WiFi及多数设备蜂窝网络环境下可正常向EC2实例发送JSON,但部分设备使用蜂窝网络时完全无法发送数据,无错误码返回,仅在重连WiFi时出现超时;受影响用户每次生成的相似JSON对象,在蜂窝网络下均发送失败。
private suspend fun sendJsonFile(file: File) { val url = URL(EC2_URL) val urlConnection = url.openConnection() as HttpURLConnection try { sendJsonFileLog = "Preparing to send file: ${file.name}" // Set timeouts for connection and read operations urlConnection.connectTimeout = 50000 urlConnection.readTimeout = 100000 urlConnection.requestMethod = "POST" urlConnection.setRequestProperty("Content-Type", "application/json") urlConnection.setRequestProperty("Content-Encoding", "gzip") urlConnection.doOutput = true // Read file and compress JSON data val jsonInputString = file.readText() val byteArrayOutputStream = ByteArrayOutputStream() GZIPOutputStream(byteArrayOutputStream).use { gzipOutputStream -> gzipOutputStream.write(jsonInputString.toByteArray()) } val compressedData = byteArrayOutputStream.toByteArray() sendJsonFileLog = "JSON data compressed" // Send compressed JSON data urlConnection.outputStream.use { os -> os.write(compressedData) os.flush() } sendJsonFileLog = "Compressed data sent" // Handle HTTP response codes val responseCode = urlConnection.responseCode sendJsonFileLog += " - Response code: $responseCode" if (responseCode == HttpURLConnection.HTTP_OK) { file.delete() sendJsonFileLog += " - File deleted." updateList() } else { handleHttpError(responseCode, urlConnection.responseMessage) } } catch (e: IOException) { sendJsonFileLog = "Network error: ${e.localizedMessage}" handleNetworkError(e) } catch (e: Exception) { sendJsonFileLog = "Unexpected error: ${e.localizedMessage}" handleUnexpectedError(e) } finally { urlConnection.disconnect() sendJsonFileLog += " - Connection closed." } }
可能的原因及排查步骤
运营商蜂窝网络的APN/代理限制
部分运营商的蜂窝网络会拦截特定格式的HTTP请求,比如对Content-Encoding: gzip的POST请求有过滤,或者APN设置中默认启用了代理导致请求被吞。可以让用户:- 检查设备APN设置,切换为运营商默认APN,关闭手动代理
- 尝试切换4G/5G网络模式,测试是否能发送成功
超时设置未覆盖蜂窝网络的慢连接场景
当前connectTimeout=50000ms、readTimeout=100000ms,但部分蜂窝网络建立连接或传输数据的时间更长,导致请求卡在建立连接阶段,未触发超时逻辑。建议临时调大超时时间(比如connectTimeout=60000ms、readTimeout=120000ms),观察是否会出现明确的超时错误,而非无响应。Gzip压缩的兼容性问题
代码中使用GZIP压缩JSON,但部分蜂窝网络的中间网关可能无法正确解析压缩后的数据流,直接丢弃请求。可以临时注释掉压缩逻辑,直接发送未压缩的JSON:// 注释压缩相关代码,直接发送原JSON val compressedData = jsonInputString.toByteArray() sendJsonFileLog = "Using uncompressed JSON data"如果发送成功,说明是压缩相关的问题,可能需要调整压缩方式(比如确保GZIP流正确关闭,或添加
Content-Length头)。HttpURLConnection的兼容性缺陷
Android系统的HttpURLConnection在部分设备和网络环境下存在兼容性问题,比如无法正确处理蜂窝网络下的TCP连接复用、分块编码等。建议替换为OkHttp库,它对各种网络环境的兼容性更好:// 示例:用OkHttp实现发送压缩JSON private suspend fun sendJsonFileWithOkHttp(file: File) { val client = OkHttpClient.Builder() .connectTimeout(60, TimeUnit.SECONDS) .readTimeout(120, TimeUnit.SECONDS) .build() val jsonInputString = file.readText() val compressedData = ByteArrayOutputStream().use { baos -> GZIPOutputStream(baos).use { it.write(jsonInputString.toByteArray()) } baos.toByteArray() } val request = Request.Builder() .url(EC2_URL) .post(RequestBody.create(MediaType.parse("application/json"), compressedData)) .header("Content-Encoding", "gzip") .build() try { client.newCall(request).execute().use { response -> sendJsonFileLog = "Response code: ${response.code()}" if (response.isSuccessful) { file.delete() sendJsonFileLog += " - File deleted." updateList() } else { handleHttpError(response.code(), response.message()) } } } catch (e: IOException) { sendJsonFileLog = "Network error: ${e.localizedMessage}" handleNetworkError(e) } }JSON内容的特殊性触发拦截
用户每次生成的相似JSON可能包含特定关键词、特殊字符或大小刚好触发运营商的安全策略拦截。可以尝试修改JSON内容(比如简化内容、替换敏感字符),测试是否能发送成功;如果能,说明是内容本身的问题,需要调整JSON结构或内容。
内容的提问来源于stack exchange,提问作者John Mulholland

