PHP API 不能与改造/gson 结合使用

Posted

技术标签:

【中文标题】PHP API 不能与改造/gson 结合使用【英文标题】:PHP API not working in conjuntion with retrofit/gson 【发布时间】:2021-04-28 00:44:45 【问题描述】:

我无法让我的 REST API 使用改造/gson 处理来自我的 android 应用程序的 POST 请求。支持 REST API 的功能是接受非常基本的 JSON 解码,在其上运行一系列 SQL 查询,然后将格式化的 JSON 数据返回给应用程序。

我知道问题不在于 API 逻辑,当我将传入的 JSON 数据硬编码或将 JSON 响应硬编码到 php 中时,API 工作正常。当我需要使用来自应用程序的 POST 请求传递 JSON 时,问题就开始了。我总是得到以下例外:FATAL EXCEPTION: DefaultDispatcher-worker-1FATAL EXCEPTION: DefaultDispatcher-worker-2 传入的 JSON 来自应用程序。

我尝试了 3 种接收传入 JSON 的方法。第一个是使用$jsonobj = http_get_request_body();函数,第二个是$jsonobj = file_get_contents('php://input');,第三个是 $jsonobj = $_POST['code'];,最后一个很有趣。我不知道['here'] 中的内容是什么,或者名称是什么,所以我可以使用它。我已经尝试在此处更改 ['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);

如果不是 JSON 接收器,这将有效。

还有一个很好的机会,我什至根本不发送 JSON,更不用说有效的 JSON。我知道有记录出站 JSON 的方法,但对于我的生活,我无法让它们工作。所以在这里我将发布一些我的android代码。

我的 API 接口

interface API 
    @POST("posttest.php")
    suspend fun postit(@Body post: String): Phone

我在这种情况下使用上述接口

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 
               //logic
        catch (e: Exception)
            //error handling
        
    

我想从房间数据库中提取 JSON,但我还没有这样做,所以我只对 JSON 进行了硬编码;它看起来像这样。

    private var test = "[\"text1\", \"text2\", \"text3\"]"

感谢您的宝贵时间。

【问题讨论】:

你可以尝试在没有 json_decode 和 SQL 逻辑的情况下返回 $jsonobj 并将其登录到 android 以检查你发送的内容。 好主意,我该怎么做? 我的答案在下面... 【参考方案1】:

以下是仅用于与 API 建立应用程序连接的代码。您将根据自己的需求调整其他所有内容(改造请求、响应、json 编码)

在 Android 应用中关注日志

我强烈建议您不要在没有数据验证的情况下查询数据库并使用 PDO

最好使用一些 php 框架的 api,如 Slim、Laravel、Lumen

您可以使用最常用的类型之一发布请求:

application/x-www-form-urlencoded = 参数编码 application/json = 发送 json 数据 //用于你的情况 multipart/form-data = 图片等文件

你的 PHP 脚本应该是这样的

if($_SERVER["REQUEST_METHOD"] == "POST")
    
    //TODO this is only example to get and return json data
    
    $jsonobj = file_get_contents('php://input');
    $json = json_decode($jsonobj);
    
    $response = array(
        "raw" => $jsonobj,
        "json" => $json
    );
    
    echo json_encode($response);
else
    //Send a 405 Method Not Allowed
    http_response_code(405);
    exit;

接口接口

interface API 
    @POST("posttest.php")
    suspend fun postIt(@Body requestBody: RequestBody): Response<ResponseBody>

和主要的

val api = Retrofit.Builder()
                .baseUrl(BASE_URL)
                //.addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(API::class.java);

        val test = "[\"text1\", \"text2\", \"text3\"]";  //hardcoded by you
        val requestBody = test.toRequestBody("application/json".toMediaTypeOrNull())

        GlobalScope.launch(Dispatchers.IO) 
            val response = api.postIt(requestBody)
            //withContext(Dispatchers.Main) 
                try 
                    if (response.isSuccessful) 
                        Log.i("RESPONSE", "DATA: " + response.body()?.string());
                     else 
                        Log.i("RESPONSE", "ERROR: " + response.errorBody()?.string());
                    

                    Log.i("RESPONSE", "RAW: " + response.raw());
                 catch (e: Exception) 
                    e.printStackTrace();
                    //error handling
                
            //
        

【讨论】:

感谢您在此回复中投入的时间和精力。我根据您的规范制作了一个新的应用程序和 PHP 脚本来测试 API,我在 logcat 中获得了这两项。 apitest I/RESPONSE: DATA: "raw":"[\"text1\", \"text2\", \"text3\"]","json":["text1","text2","text3"]apitest I/RESPONSE: RAW: Responseprotocol=http/1.1, code=200, message=OK, url=http://10.0.2.2/posttest2.php。我忽略指定这是否也出现在日志 cat `com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $` 我刚刚准备好你的代码来发送你的硬编码 json,然后是 php 脚本来检索它,解码它并以原始和 json 格式返回给应用程序......我不知道是什么您想发送并返回到应用程序..您必须根据需要调整改造...尝试发送其他内容,插入数据库并返回您想要的内容 这似乎是一个奇怪的问题,但是哪个变量将发送回 PHP 脚本的 JSON 发回?因为如果 JSON 包含所有额外的内容,那么脚本无法正常工作是有意义的 在这种情况下,您从 android 发送的 json 将以原始和 json 格式返回给您,并带有 echo json_encode ($response);如果我很好地理解了这个问题...... $json 变量包含解​​码后的 json,你可以用它做任何你想做的事情【参考方案2】:

事实证明问题出在我的 PHP API code 非常感谢用户:404438 @kylexy1357 给了我日志记录代码,所以我可以看到发生了什么

他的code

val gson = GsonBuilder()
                .setLenient()
                .create()

  val builder = OkHttpClient().newBuilder()
        builder.readTimeout(120, TimeUnit.SECONDS)
        builder.connectTimeout(30, TimeUnit.SECONDS)

        if (BuildConfig.DEBUG) 
            val interceptor = HttpLoggingInterceptor()
            interceptor.level = HttpLoggingInterceptor.Level.BASIC
            builder.addInterceptor(interceptor)
        
  val client = builder.build()


  val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(client)
                .build()

【讨论】:

以上是关于PHP API 不能与改造/gson 结合使用的主要内容,如果未能解决你的问题,请参考以下文章

使用改造获取带有 GSON 的嵌套 JSON 对象

如何在不使用 GSON 或 android 中的任何其他库的情况下使用改造以字符串形式获得响应 [重复]

改造+GSON+ORM

如何使用改造和 gson 异步解析 json

改造:来自 gson 转换体的原始响应体

如何使用 gson/retrofit 获取对象数组?