即使服务器发送非空响应,响应正文也为空

问题描述 投票:0回答:1

我正在尝试使用 jetpack compose + kotlin 为客户端制作一个 Android 应用程序,并为服务器端使用 Nodejs +express.js 来制作我的 RESTApi。

对于我的端点之一:

@POST /getUserIdAndName

我的服务器期望请求正文为:

 {
    "id": Int
}

并以以下格式给出响应:

{
    "code": Int,
    "body": [
                {
                    "id": Int,
                    "name": String,
                    "photo": String
                },
                {
                    "id": Int,
                    "name": String,
                    "photo": String
                },
... so on
            ]
}

对于我的客户端,我以这种方式对响应进行建模:

  1. 我的主要回应课:

    data class DetailsResponseDto<T:ResponseBody>(
        val code: Int,
        val body: T?,
        val message: String
    )
    
  2. 我对此端点的响应正文:

    import com.example.hola.core.domain.utils.ResponseBody
    import com.squareup.moshi.Json
    import com.squareup.moshi.JsonClass
    
    data class UserIdAndNameResponse(
        val id : Int?,
        val name : String?,
        val photo: String?
    )
    
    @JsonClass(generateAdapter = true)
    data class UsersList(
        @Json(name = "body")
        val body : List<UserIdAndNameResponse>
    ) : ResponseBody
    
  3. 端点:

    @POST("/getUserIdAndName")
    suspend fun getUserIdAndName(@Body myUserId: Map<String, Int>) : DetailsResponseDto<UsersList>
    

    “ResponseBody”只是一个标记接口,我在应用程序的架构中使用了它,以便所有不同类型的响应正文可以具有相同的标识。

    interface ResponseBody
    

当我用它从 api 获取数据时,它给出的结果是我的响应正文为空。但同时,当我检查我的服务器日志时,它给出了正确的输出。我也向 ChatGPT 询问了这个问题,但我无法得到任何也应该尊重我的应用程序的架构约束的解决方案。

限制如下:

  1. 我无法删除“ResponseBody”标记接口来简化我的响应数据类(ChatGPT 已经建议这样做),因为正如我所说,这会破坏我的架构。

  2. 我无法更改服务器端请求/响应格式,因为在使用同一端点的其他情况下,我只需要这种格式的数据。

如何解决这个问题?

我的端点的客户端实现如下:

interface GetOtherUsersDetailAbstract {
    suspend fun <D>getUserIdAndNames(myUserId: Int) : Result<D, Error>
}
class EstablishNewConversations : GetOtherUsersDetailAbstract {


    private val TAG = "EstablishNewConversations"
    //Use retrofit to send the request
    val moshi = Moshi.Builder()
        .add(KotlinJsonAdapterFactory())
        .build()

    val api : HolaAppRestApi = Retrofit.Builder()
        .baseUrl(BuildConfig.BASE_URL)
        .addConverterFactory(MoshiConverterFactory.create(moshi))
        .build()
        .create()

    override suspend fun <D> getUserIdAndNames(myUserId: Int): com.example.hola.core.domain.utils.Result<D, Error> {
        Log.d(TAG,"Get user id and names called")
        val requestBody = mapOf("id" to myUserId)

        return try{
            val response = api.getUserIdAndName(requestBody)
            Log.d(TAG, "Raw API Response: ${response}")

            if (response.body != null){

                detailResponseToResult(api.getUserIdAndName(requestBody))
                    .mapAResult { usersList: UsersList? ->
                        if (usersList == null) {
                            Log.d(TAG,"Users list is null")
                            UsersList(emptyList()) as D
                        }
                        Log.d(TAG,"Users list is not null: $usersList")

                        usersList as D
                    }

            } else{
                Log.d(TAG,"Response body is null")
                Result.Error(ConversationError.NO_CONVERSATION_FOUND)
            }

        }catch (e:Exception){
            Log.e(TAG,"Error fetching user ID and names: ${e.message}",e)
            Result.Error(ConversationError.UNEXPECTED_ERROR)
        }
    }
}

日志是这样的:

2025-01-04 04:52:19.179 17837-17862 EstablishN...versations com.example.hola                     D  Get user id and names called
2025-01-04 04:52:19.998 17837-17862 EstablishN...versations com.example.hola                     D  Raw API Response: DetailsResponseDto(code=1, body=null, message=Success)
2025-01-04 04:52:19.998 17837-17862 EstablishN...versations com.example.hola                     D  Response body is null

我的服务器端实现是:

exports.getUserIdAndName = async (req, res, next) => {
  const body = req.body;
  console.log("Got id as : ", body.id);
  console.log("Type is : ", typeof body.id);

  //Constructing base url
  const baseUrl = `${req.protocol}://${req.get("host")}`;

  if (!body.id) {
    return res.status(400).json({
      code: 0,
      body: null,
      error: "Invalid request. 'id' is required.",
    });
  }
  console.log("id is correct");

  try {
    const userIdAndNameList = await UserDetails.getUserIdAndNameList(
      body.id,
      baseUrl
    );

    if (userIdAndNameList.code !== 1) {
      console.log(`returning userList as ${JSON.stringify(userIdAndNameList)}`);
      return res.status(500).json({
        code: userIdAndNameList.code,
        body: null,
        message: userIdAndNameList.message,
      });
    }
    console.log(`returning userList as ${JSON.stringify(userIdAndNameList)}`);

    return res.status(200).json({
      code: 1,
      body: userIdAndNameList.data,
      message: userIdAndNameList.message,
    });
  } catch (err) {
    return res.status(500).json({
      code: mapError("remoteDatabaseErr", "crudOperationErr", "unknownError"),
      body: null,
      message: "Some Unknown Internal error happened",
    });
  }
};
node.js json kotlin android-jetpack-compose http-post
1个回答
0
投票

你的nodejs应用程序中是否实现了bodyparser?如果不是,那么body将永远为null。nodejs在控制台的输出是什么?

© www.soinside.com 2019 - 2024. All rights reserved.