You need to enable JavaScript to run this app. PHP REST API 无法与基于Retrofit/Gson的Android应用POST请求正常对接
优惠活动
大模型
产品
解决方案
定价
更多

PHP REST API 无法与基于Retrofit/Gson的Android应用POST请求正常对接

对接故障背景
  • 目标功能:自研REST API接收安卓应用通过Retrofit/Gson发起的POST JSON请求,解析后执行SQL查询,返回格式化JSON响应。
  • 已验证正常的环节:PHP端硬编码传入JSON、硬编码返回JSON时,所有API逻辑、SQL执行流程均可正常运行。
  • 故障表现:
    • 从应用侧通过POST传输JSON时,安卓端抛出致命错误:FATAL EXCEPTION: DefaultDispatcher-worker-1 或 FATAL EXCEPTION: DefaultDispatcher-worker-2
    • PHP端尝试3种JSON接收方案均未生效:
      1. $jsonobj = http_get_request_body();
      2. $jsonobj = file_get_contents('php://input');
      3. $jsonobj = $_POST['code']; —— 不确定字段名规范,尝试替换为['text']等字段名均无返回
    • 现有PHP脚本结构:
      //database config here.
      if($_SERVER["REQUEST_METHOD"] == "POST"){
          //method of reciving JSON here.
          $obj = json_decode($jsonobj);
          //SQL logic here.
          echo json_encode($return);
      }
      
  • 安卓端现有代码片段:
    1. API接口定义:
      interface API {
          @POST("posttest.php")
          suspend fun postit(@Body post: String): Phone
      }
      
    2. 接口调用逻辑:
      val api = Retrofit.Builder()
          .baseUrl(BASE_URL)
          .addConverterFactory(GsonConverterFactory.create())
          .build()
          .create(API::class.java)
      GlobalScope.launch(Dispatchers.IO) {
          val response = api.postit(test)
          try {
              //业务逻辑
          } catch (e: Exception) {
              //错误处理
          }
      }
      
    3. 当前硬编码测试数据(原计划从Room读取数据,暂未实现):
      private var test = "[\"text1\", \"text2\", \"text3\"]"
      
故障定位

根本原因1:Retrofit请求序列化逻辑错误

  • 搭配默认GsonConverterFactory使用@Body注解传String类型参数时,Gson会对传入的字符串执行二次序列化:原本传入的合法JSON数组字符串["text1","text2","text3"],会被转义为嵌套格式的字符串报文"[\"text1\", \"text2\", \"text3\"]"(外层包裹双引号、内部双引号被转义)。PHP端读到这个转义后的字符串后,json_decode解析失败得到null,后续操作null值直接抛出运行时错误。
  • 关于$_POST的使用误区:$_POST仅能解析application/x-www-form-urlencoded格式的表单POST参数,Retrofit通过@Body发送的是application/json格式的原始报文,不会填充到$_POST数组中,无论替换什么字段名都无法读取到值。

根本原因2:协程异常捕获范围错误

  • 安卓端的try-catch仅包裹了请求成功后的业务逻辑,网络请求调用、响应解析阶段抛出的异常(如PHP端返回报错文本而非合法JSON)未被捕获,直接触发DefaultDispatcher的未捕获致命异常,即日志中看到的FATAL EXCEPTION: DefaultDispatcher-worker-*。
修复方案

安卓端调整

  1. 避免手动传递JSON字符串被二次序列化:
    • 方案一:定义与传输结构匹配的数据类,直接传对象给Retrofit,由Gson自动完成序列化:
      // 对应传输结构的数据类
      class TestRequest(val data: List<String> = listOf("text1", "text2", "text3"))
      // 接口定义修改为
      interface API {
          @POST("posttest.php")
          suspend fun postit(@Body post: TestRequest): Phone
      }
      
    • 方案二:若必须传递原始JSON字符串,需手动指定请求Content-Type为application/json,跳过Gson对字符串的序列化处理,避免报文被转义。
  2. 扩大协程异常捕获范围,覆盖全流程网络请求逻辑:
    GlobalScope.launch(Dispatchers.IO) {
        try {
            val response = api.postit(test)
            // 后续业务逻辑
        } catch (e: Exception) {
            // 错误处理,打印堆栈定位具体报错
        }
    }
    

PHP端调整

  1. 统一使用file_get_contents('php://input')读取原始请求报文,替换原有接收方式:
    if($_SERVER["REQUEST_METHOD"] == "POST"){
        // 读取原始JSON请求体
        $jsonobj = file_get_contents('php://input');
        $obj = json_decode($jsonobj, true);
        // 增加解析失败校验,避免空值触发后续逻辑报错
        if (is_null($obj)) {
            echo json_encode(["code" => 400, "msg" => "invalid request json"]);
            exit;
        }
        //SQL logic here.
        echo json_encode($return);
    }
    
  2. 增加调试日志:将读取到的原始php://input内容写入本地日志文件,确认实际收到的报文格式,避免盲目排查。

内容的提问来源于stack exchange,提问作者m.seigmiller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.07 14:36:10