从OkHttpClient+Gson转Volley+JSONObject遇307错误求助
从OkHttpClient+Gson迁移到Volley+JSONObject时的307重定向错误解决
问题描述
我是API集成领域的新手,原本用OkHttpClient+Gson实现的音频评分服务请求功能运行正常,但由于应用另一部分依赖Volley库和JSONObject,遂进行迁移。修改后遇到错误:
E [93] NetworkUtility.shouldRetryException: Unexpected response code 307 for https://url/score
尝试处理重定向后,要么出现类似错误,要么请求无限循环,恳请帮助理解错误含义并提供解决办法。
原有OkHttpClient+Gson实现代码
private suspend fun scoreAudioWithASR(audioUri: Uri, text: String): String { val audioBuffer = uriToBase64(context, audioUri) val requestDict = mapOf( "lang_code" to "voice", "gender" to "M", "text" to text, "audio" to audioBuffer, "tag" to "test" ) // inspect the data produced for debugging purposes // saveRequestData(requestDict) val gson = Gson() val requestBody = gson.toJson(requestDict) .toRequestBody("json; charset=utf-8".toMediaTypeOrNull()) val requestBodyJsonString = gson.toJson(requestDict) Log.d("JSON Object", requestBodyJsonString) val request = Request.Builder() .url("https://url/score") .post(requestBody) .build() val client = OkHttpClient.Builder() .connectTimeout(60, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .writeTimeout(60, TimeUnit.SECONDS) .build() return withContext(Dispatchers.IO) { try { client.newCall(request).execute().use { response -> if (!response.isSuccessful) throw IOException("Unexpected code $response") val responseDict = gson.fromJson(response.body?.string(), Map::class.java) val utteranceDp = responseDict["utterance_dp"] as Double Log.d("utteranceDp",utteranceDp.toString() ) val utteranceThresholds = responseDict["utterance_thresholds"] as List<Double> Log.d("utteranceThresholds",utteranceThresholds.toString() ) if (utteranceDp > utteranceThresholds[1]) "good" else "try again" } } catch (e: Exception) { Log.e("ASRScore", "Error making ASR request", e) "error message." } } }
迁移后的Volley代码
private suspend fun scoreAudioWithASR( audioUri: Uri, text: String, ): String { return suspendCoroutine { continuation -> val audioBuffer = uriToBase64(context, audioUri) val url = "https://url/score/" val jsonObject = JSONObject().apply { put("lang_code", "zul_kids") put("gender", "M") put("text", text) put("audio", audioBuffer) put("tag", "test") } // Convert JSON object to a formatted string val jsonString = jsonObject.toString(4) // Log the formatted JSON string Log.d("JSON Object", jsonString) val queue = Volley.newRequestQueue(context) val jsonObjectRequest = JsonObjectRequest( Request.Method.GET, url, jsonObject, { response -> // Handle successful response val responseDict = response as Map<*, *> val utteranceDp = responseDict["utterance_dp"] as Double val utteranceThresholds = responseDict["utterance_thresholds"] as List<Double> val result = if (utteranceDp > utteranceThresholds[1]) { "WWell done!" } else { "Not good, try again" } continuation.resume(result) }, { error -> // Handle Volley error Log.e("API Error", "Error fetching game configuration: ${error.message}") continuation.resumeWithException(error) } ) queue.add(jsonObjectRequest) } }
错误原因分析
- 307临时重定向:该状态码表示请求需要临时转发到新的URL,且必须保持原请求的方法和请求体不变。OkHttpClient默认会自动处理这类重定向,但Volley的默认实现存在缺陷。
- 请求方法不匹配:原有代码使用POST方法发送请求体,但迁移后的代码误用了GET方法。GET请求携带JSON体不符合HTTP规范,服务器返回307后Volley无法正确处理请求体的重发,导致错误或循环。
- URL不一致:原有URL是
https://url/score,迁移后的URL多了末尾斜杠https://url/score/,服务器可能因此返回重定向,进一步触发Volley的处理问题。 - 参数不一致:原有代码的
lang_code是voice,迁移后改成了zul_kids,可能导致服务器返回非预期响应。
解决办法及修正后的代码
关键修正点
- 将请求方法改回POST,与原有代码保持一致
- 统一URL,去掉末尾多余的斜杠
- 修正
lang_code参数,保持和原有代码一致 - 确保请求头设置正确的
Content-Type为application/json
修正后的Volley代码
private suspend fun scoreAudioWithASR(audioUri: Uri, text: String): String { return suspendCoroutine { continuation -> val audioBuffer = uriToBase64(context, audioUri) val url = "https://url/score" // 统一URL,去掉末尾斜杠 val jsonObject = JSONObject().apply { put("lang_code", "voice") // 修正参数,和原有代码一致 put("gender", "M") put("text", text) put("audio", audioBuffer) put("tag", "test") } val jsonString = jsonObject.toString(4) Log.d("JSON Object", jsonString) val queue = Volley.newRequestQueue(context) // 使用POST方法,正确发送JSON请求体 val jsonObjectRequest = object : JsonObjectRequest( Request.Method.POST, url, jsonObject, { response -> try { val utteranceDp = response.getDouble("utterance_dp") val utteranceThresholds = response.getJSONArray("utterance_thresholds") // 将JSONArray转换为List<Double> val thresholdsList = mutableListOf<Double>() for (i in 0 until utteranceThresholds.length()) { thresholdsList.add(utteranceThresholds.getDouble(i)) } val result = if (utteranceDp > thresholdsList[1]) { "Well done!" } else { "Not good, try again" } continuation.resume(result) } catch (e: JSONException) { Log.e("API Parse Error", "Failed to parse response", e) continuation.resumeWithException(e) } }, { error -> Log.e("API Error", "Error making ASR request: ${error.message}", error) continuation.resumeWithException(error) } ) { // 确保请求头设置正确的Content-Type override fun getHeaders(): MutableMap<String, String> { val headers = HashMap<String, String>() headers["Content-Type"] = "application/json; charset=utf-8" return headers } } // 设置超时时间,和原有代码保持一致 jsonObjectRequest.setRetryPolicy(DefaultRetryPolicy( 60000, // 60秒超时 DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT )) queue.add(jsonObjectRequest) } }
额外建议
如果服务器仍返回307且Volley无法处理,可自定义Volley的HurlStack来处理重定向:
val stack = object : HurlStack() { override fun performRequest(request: Request<*>?, additionalHeaders: MutableMap<String, String>?): HttpResponse { val httpResponse = super.performRequest(request, additionalHeaders) val statusCode = httpResponse.statusCode if (statusCode == 307) { val location = httpResponse.headers.get("Location") if (!location.isNullOrEmpty()) { // 重新构造请求到新URL,保持方法和请求体 val newRequest = Request.Builder() .url(location) .method(request?.method, request?.body) .headers(request?.headers) .build() return super.performRequest(newRequest, additionalHeaders) } } return httpResponse } } val queue = Volley.newRequestQueue(context, stack)
内容的提问来源于stack exchange,提问作者Sthesh
相关产品推荐
相关产品推荐

