使用Retrofit和Gson解析API时响应正文为空

cnjp1d6j  于 2022-11-06  发布在  其他
关注(0)|答案(1)|浏览(222)

我在这个项目上使用了Retrofit和Gson。我试图登录,我应该得到一个用户ID的响应,faunadb_token,以及填充了用户数据的数据列表。

"body": "{\n    \"content\": {\n        \"id\": \"328803596056396364\",\n        \"faunadb_token\": \"fauna fnEEnk81KUACTwSP8HIOwApJqbjNg-u4fqC9q6Da2FvPTP2esYs\",\n        \"data\": {\n            \"name\": \"test2\",\n            \"email\": \"bowner@gmail.com\",\n            \"role\": \"admin\",\n            \"organization_id\": \"328992226856141394\",\n            \"address\": \"address local\",\n            \"birthdate\": \"2000-04-13\",\n            \"phonenumber\": \"0811033222\",\n            \"s3_image\": \"https://assignmentsystem.s3.ap-southeast-1.amazonaws.com/userimages/0abf8e6b-c2b2-4e49-9a88-10ffb3fffaba-272327.jpg\"\n        }\n    },\n    \"message\": \"Successful Login\",\n    \"errors\": []\n}"

然而,当我登录时,我得到的statusCode为200,而我的response.body全部为空。

但是,在终端中,我可以看到实际的响应主体在那里,我只是不知道如何获得它(倒数第三行)。

I/okhttp.OkHttpClient: <-- 200 https://api.absensia.online/backend/user/login (1111ms)
I/okhttp.OkHttpClient: content-type: application/json; charset=utf-8
I/okhttp.OkHttpClient: x-powered-by: Express
I/okhttp.OkHttpClient: access-control-allow-origin: *
I/okhttp.OkHttpClient: etag: W/"1b0-6FklyrUjQI2dIrZLhEXcT1rvf1A"
I/okhttp.OkHttpClient: vary: Accept-Encoding
I/okhttp.OkHttpClient: date: Mon, 27 Jun 2022 07:45:02 GMT
I/okhttp.OkHttpClient: x-kong-upstream-latency: 264
I/okhttp.OkHttpClient: x-kong-proxy-latency: 1
I/okhttp.OkHttpClient: via: kong/2.8.1
I/okhttp.OkHttpClient: {"content":{"id":"328803596056396364","faunadb_token":"fauna fnEEqE4wt-ACUQSP8HIOwApJ7n1pLvPWUfBNciPtrEL0t1ifoT8","data":{"name":"test2","email":"bowner@gmail.com","role":"admin","organization_id":"328992226856141394","address":"address local","birthdate":"2000-04-13","phonenumber":"0811033222","s3_image":"https://assignmentsystem.s3.ap-southeast-1.amazonaws.com/userimages/default.png"}},"message":"Successful Login","errors":[]}
I/okhttp.OkHttpClient: <-- END HTTP (432-byte body)
D/EGL_emulation: app_time_stats: avg=16.10ms min=1.92ms max=565.09ms count=42

下面是我的一些代码:
Api配置

object ApiConfig {
    private const val BASE_URL = "https://api.absensia.online/backend/"
    private val client: Retrofit
        get() {
            val gson = GsonBuilder().setLenient().create()

            val interceptor = HttpLoggingInterceptor()
            interceptor.level = HttpLoggingInterceptor.Level.BODY

            val client: OkHttpClient = OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .connectTimeout(40, TimeUnit.SECONDS)
                .readTimeout(40, TimeUnit.SECONDS)
                .writeTimeout(40, TimeUnit.SECONDS)
                .build()

            return Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(client)
                .build()
        }

    val instanceRetrofit: ApiService
        get() = client.create(ApiService::class.java)
}

Api服务

interface ApiService {

    @FormUrlEncoded
    @POST("user/login")
    suspend fun login(
        @Field("email") email:String,
        @Field("password") password:String,
    ): Response<LoginResponse>

    @GET("user/logout")
    suspend fun logout(
        @Header("Auth") auth: String
    ): Response<ResponseAuth>

}

登录响应类

data class LoginResponse(

    @SerializedName("id")
    var id: String?,

    @SerializedName("faunadb_token")
    var faunadb_token: String?,

    @SerializedName("data")
    var data: User?
)

资料档案库

class Repository {

    suspend fun login(email: String, password: String): Response<LoginResponse>{
        return ApiConfig.instanceRetrofit.login(email, password)
    }

    suspend fun logout(auth: String): Response<ResponseAuth>{
        return ApiConfig.instanceRetrofit.logout(auth)
    }
}

身份验证视图模型

class AuthenticationViewModel(private val repository: Repository): ViewModel() {

    var loginResponse: MutableLiveData<Response<LoginResponse>> = MutableLiveData()
    var logout: MutableLiveData<Response<ResponseAuth>> = MutableLiveData()

    fun login(email: String, password: String){
        viewModelScope.launch {
            val response = repository.login(email, password)
            loginResponse.value = response
        }
    }

    fun logout(auth: String){
        viewModelScope.launch {
            val response = repository.logout(auth)
            logout.value = response
        }
    }

}

身份验证视图模型工厂

class AuthenticationViewModelFactory(private val repository: Repository): ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return AuthenticationViewModel(repository) as T
    }

}

登录活动

class LoginActivity : AppCompatActivity() {

    private lateinit var loginpref: SharedPref
    private lateinit var viewModel: AuthenticationViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_masuk)
        loginpref = SharedPref(this)

        val masuk = findViewById<Button>(R.id.masuk_btn)
        masuk.setOnClickListener {
            masukButton()
        }

        buttonsMasukTest()
    }

    private fun masukButton(){
        val masukEmail = findViewById<TextInputEditText>(R.id.masukHpEmail)
        val masukPass = findViewById<TextInputEditText>(R.id.masukPass)

        val masukEmailLayout = findViewById<TextInputLayout>(R.id.masukHpEmail_layout)
        val masukPassLayout = findViewById<TextInputLayout>(R.id.masukPass_layout)

        val loadMasuk = findViewById<ProgressBar>(R.id.load_masuk)

        masukEmailLayout.isErrorEnabled = false
        masukPassLayout.isErrorEnabled = false

        if (masukEmail.text.toString().isEmpty()) {
            masukEmailLayout.isErrorEnabled = true
            masukEmailLayout.error = "Mohon mengisi kolom ini"
            masukEmailLayout.requestFocus()
            return
        }
        if (masukPass.text.toString().isEmpty()) {
            masukPassLayout.isErrorEnabled = true
            masukPassLayout.error = "Mohon mengisi kolom ini"
            masukPassLayout.requestFocus()
            return
        }
        if (!android.util.Patterns.EMAIL_ADDRESS.matcher(masukEmail.text.toString()).matches()){
                masukEmailLayout.isErrorEnabled = true
                masukEmailLayout.error = "Mohon mengisi email dengan benar"
                masukEmailLayout.requestFocus()
                return
        }

        loadMasuk.visibility = View.VISIBLE

        val repository = Repository()
        val viewModelFactory = AuthenticationViewModelFactory(repository)
        viewModel = ViewModelProvider(this, viewModelFactory).get(AuthenticationViewModel::class.java)
        viewModel.login(
            masukEmail.text.toString(),
            masukPass.text.toString())
        viewModel.loginResponse.observe(this, Observer { response ->
            if (response.isSuccessful){
                loadMasuk.visibility = View.GONE

                val respon = response.body()

                loginpref.setStatusLogin(true)

                respon?.data?.let { loginpref.setUser(it) }
                respon?.faunadb_token?.let { loginpref.saveToken(it) }

                /**
                 * Momentary textview so I can know my respon
                 */
                findViewById<TextView>(R.id.testing).setText(respon.toString())

                /**
                 * I comment the section where it start the next activity for testing purposes
                 */
//                val intent = Intent(this@LoginActivity, MainActivity::class.java)
//                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
//                startActivity(intent)
//                finish()
//                Toast.makeText(this@LoginActivity, "Welcome " + masukEmail.text.toString(), Toast.LENGTH_SHORT).show()

            }else if(!response.isSuccessful){
                loadMasuk.visibility = View.GONE
                Toast.makeText(this@LoginActivity, "Login failed: Your Email or Password is Incorrect : "+response, Toast.LENGTH_SHORT).show()
            }
        })

    }

    private fun buttonsMasukTest(){
        val testMasuk = findViewById<Button>(R.id.masuk_btnTest)

        testMasuk.setOnClickListener {
            val intent = Intent (this@LoginActivity, MainActivity::class.java)
            loginpref.setStatusLogin(true)
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
            startActivity(intent)
            finish()
        }
    }
}

我是新的Kotlin,我试图阅读和观看从几个来源有关Okhttp,翻新,gson,和viewmodel,但没有在解决这个问题的效用.任何帮助和建议将不胜感激,关于我如何可以得到响应体.谢谢.

628mspwn

628mspwn1#

@FormUrlEncoded
@POST("user/login")
suspend fun login(
    @Field("email") email:String,
    @Field("password") password:String,
): Response<ContentResponse>

data class ContentResponse(
     @SerializedName("content")
     val loginResponse: LoginResponse
)

也许这可以帮助您。您正在内容节点中获取数据,因此

相关问题