You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android端Volley调用API出现403 AuthFailureError求助

解决Volley调用API返回AuthFailureError 403的问题(Postman正常但Android异常)

问题描述

同一个API在Postman中可正常获取响应,但在Android设备上用Volley调用时抛出com.android.volley.AuthFailureError 403错误。调用API前需设置25个参数,Postman截图可验证API本身正常。已尝试设置Content-Type、Base64编码、Token校验等方案,问题仍未解决。当前网络调用代码如下:

import android.app.Activity
import android.content.Intent
import android.util.Base64
import android.util.Log
import com.android.volley.*
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.softnoesis.maxotexmart.login.LoginActivity
import com.softnoesis.maxotexmart.utils.AppPreference
import com.softnoesis.maxotexmart.utils.CommonUtils
import com.softnoesis.maxotexmart.utils.Constant.Companion.NETWORK_API_CALL
import com.softnoesis.maxotexmart.utils.Constant.Companion.TAG
import org.json.JSONObject
import java.lang.reflect.Type

class NetworkAPICall {
    fun CallApplicationWS(mContext: Activity?, NetworkAPICallModel: NetworkAPICallModel,
                          NetworkAPIResponseCallback: NetworkAPIResponseCallback?) {
        Log.i(TAG, "$NETWORK_API_CALL --> CallApplicationWS")
        if (NetworkAPICallModel.getCommonUtils().isNetworkAvailable(mContext!!)) try {
            if (!NetworkAPICallModel.isShowProgress())
                NetworkAPICallModel.getCommonUtils().showProgress(mContext)
            val RequestQueue: RequestQueue = Volley.newRequestQueue(mContext)
            val StringRequest: StringRequest = object : StringRequest(NetworkAPICallModel.getRequest_type(),
                NetworkAPICallModel.getApiURL(), Response.Listener<String?> { response ->
                Log.i(TAG, "$NETWORK_API_CALL --> " +
                        "CallApplicationWS --> response")
                try{
                    NetworkAPICallModel.getCommonUtils().hideProgress()
                    if(NetworkAPICallModel.getParserType() != null) {
                        val `object`: Any = Gson().fromJson(response, NetworkAPICallModel.getParserType())
                        NetworkAPICallModel.setResponseObject(`object`)
                    }
                    NetworkAPIResponseCallback?.onSuccessResponse(JSONObject(response), NetworkAPICallModel)
                } catch(jsonException: Exception) {
                    NetworkAPICallModel.getCommonUtils().hideProgress()
                    Log.i(TAG, "$NETWORK_API_CALL --> CallApplicationWS --> response --> ${jsonException.message}")
                    try{
                        NetworkAPICallModel.getCommonUtils().hideProgress()
                    }catch (e: Exception) {
                        NetworkAPICallModel.getCommonUtils().hideProgress()
                        Log.i(TAG, "$NETWORK_API_CALL --> CallApplicationWS --> response --> ${e.message}")
                    }
                }
            },
                Response.ErrorListener { error ->
                    NetworkAPICallModel.getCommonUtils().hideProgress()
                    Log.i(TAG, "$NETWORK_API_CALL --> CallApplicationWS --> error --> ${error.message}")
                    val response: NetworkResponse = error.networkResponse
                    if (error is ServerError) {
                        try {
                            val intent = Intent(mContext, LoginActivity::class.java)
                            intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
                            mContext.startActivity(intent)
                        } catch (e1: Exception) {
                            NetworkAPICallModel.getCommonUtils().hideProgress()
                            Log.i(TAG, "$NETWORK_API_CALL --> CallApplicationWS --> error --> ${e1.message}")
                        }
                    }
                    CommonUtils().hideProgress()
                    CommonUtils().showDialog(
                        mContext,
                        """
                                            Something went wrong! Please try again later!
                                            If problem still persist, please drop mail at support@.com
                                            """.trimIndent()
                    ).show()
            }) {
                override fun getParams(): MutableMap<String, String> {
                    var params: MutableMap<String, String> = HashMap()
                    val type: Type = object : TypeToken<HashMap<String, String>>() {}.type
                    params = Gson().fromJson(NetworkAPICallModel.getJsonObjectRequest().toString(), type)
                    return params
                }

                override fun getHeaders(): MutableMap<String, String> {
                    val params: MutableMap<String, String> = HashMap()
//                     headers.put("Authorization", "Bearer " + jetEncryptor.getJwtkey());
                    if (AppPreference(mContext).isUserLogin()) {
                        params["User-Agent"]="Mozilla/5.0"
                        params["Authorization"] = "Bearer " + AppPreference(mContext).getToken()
                    }
                    return params
                }
            }
            RequestQueue.add(StringRequest)
            StringRequest.retryPolicy = DefaultRetryPolicy(
                0,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
            )
        } catch (e: Exception) {
            NetworkAPICallModel.getCommonUtils().hideProgress()
            Log.i(TAG, "$NETWORK_API_CALL --> CallApplicationWS -->${e.message}")
        } else {
            NetworkAPICallModel.getCommonUtils().hideProgress()
            CommonUtils().showDialog(mContext, "Please check you internet connection").show()
        }
    }
 }

排查与解决建议

1. 完全对比Postman与Volley的请求头

403错误大多源于权限校验不通过,必须把Postman的所有请求头(包括默认隐藏的)和Volley发送的请求头做逐行对比:

  • 在Postman中点击「Code」按钮,选择「Kotlin - Volley」生成代码,和你的代码对比请求头、参数构造逻辑
  • 检查是否遗漏了Postman中的关键头(比如Accept、Content-Type,或服务器要求的自定义头)
  • 当前代码中getHeaders()仅在用户登录时设置User-Agent和Authorization,若未登录状态下调用该API,这两个头会缺失,可能触发403

2. 验证参数构造的准确性

你通过Gson将JsonObjectRequest转成HashMap作为参数,可能存在以下问题:

  • JSON中的数值类型(整数、浮点数)被转成字符串,导致服务器校验不匹配
  • 参数键名大小写与服务器要求不一致(Postman可能不区分,但服务器严格校验)
  • 打印getParams()返回的参数Map,和Postman中发送的参数逐一核对,确保键名、值的类型、内容完全一致

3. 确认请求方法与参数传递格式

  • 核实API的请求方法(GET/POST):如果是POST请求,Volley的StringRequest默认用application/x-www-form-urlencoded格式,若Postman使用raw/JSON格式,服务器可能无法解析参数,进而返回403(部分服务器会将参数解析失败判定为权限问题)
  • 若服务器要求JSON格式的请求体,需重写getBody()和getBodyContentType()方法,替代getParams():
override fun getBody(): ByteArray {
    return NetworkAPICallModel.getJsonObjectRequest().toString().toByteArray(charset("UTF-8"))
}

override fun getBodyContentType(): String {
    return "application/json; charset=utf-8"
}

4. 确保Token的有效性与正确传递

  • 打印AppPreference(mContext).getToken()获取的Token,和Postman中使用的Token完全对比,确认一致
  • 检查Token是否过期,或是否需要配合其他参数(如设备ID、时间戳)使用
  • 部分服务器会校验Token签名,需确保Token生成的算法、密钥和服务器端一致

5. 调整重试策略的超时时间

当前代码设置超时时间为0,会导致请求立即超时,可能被服务器判定为异常请求拦截,建议设置合理的超时时间:

StringRequest.retryPolicy = DefaultRetryPolicy(
    15000, // 15秒超时
    DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
    DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
)

6. 抓包调试请求详情

使用Charles或Fiddler抓包,查看Volley发送的完整请求(包括请求头、参数、请求体),和Postman的请求做对比,这是定位差异最直接的方法。

内容的提问来源于stack exchange,提问作者user2357113

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 17:40:49