英文:
Retrofit Post Request Error - java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
问题
我正在尝试使用 Retrofit、MVVM、Coroutines 和 Hilt 发送一个 POST 请求。
在发送 POST 请求后,我得到了以下错误:
java.lang.IllegalStateException: 预期的是对象(BEGIN_OBJECT),但在第 1 行第 1 列找到了字符串(STRING),路径为 $
(我已经搜索过了,但没有找到有帮助的解决方法)
AppModule
@Provides
@Singleton
fun provideRetrofit(gson: Gson): Retrofit = Retrofit.Builder()
.baseUrl(EndPoints.BASE_URL)
.client(
OkHttpClient.Builder().apply {
if (BuildConfig.DEBUG) {
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
addInterceptor(logging)
}
}.build()
)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
@Provides
@Singleton
fun provideApiService(retrofit: Retrofit) = retrofit.create(ApiService::class.java)
ApiService
@POST(EndPoints.REGISTER_WITH_EMAIL)
suspend fun registerUserWithEmail(@Body newUser: NewUser): Response<JsonResponse>
ApiDataSource
suspend fun createNewUserEmail(newUser: NewUser) = apiService.registerUserWithEmail(newUser)
NewUser
data class NewUser(
@SerializedName("username") val userName: String?,
@SerializedName("password") val password: String?,
@SerializedName("email") val email: String?,
@SerializedName("birthday") val birthday: String?,
@SerializedName("birth_year") val birthYear: String?,
@SerializedName("fullname") val fullname: String?,
@SerializedName("gender") val gender: String?
)
RegisterRepo
suspend fun saveUserWithEmail(newUser: NewUser) = safeApiCall {
apiDataSource.createNewUserEmail(newUser)
}
RegisterViewModel
// SaveUserDetails
private val _saveDetailsEmail = MutableLiveData<Resource<JsonResponse>>()
fun doRegisterUserEmail(newUser: NewUser) = viewModelScope.launch {
try {
_saveDetailsEmail.value = registerRepo.saveUserWithEmail(newUser)
} catch (exception: Exception) {
// Handle exception
}
}
JsonResponse
data class JsonResponse(val success: String, val message: String)
RegisterFragment
val userDetails = NewUser(usernameString, passwordPassed, emailPassed, birthdayPassed, birthYearPassed, fullnameString, genderString)
registerViewModel.doRegisterUserEmail(userDetails)
registerViewModel.saveDetailsEmail.observe(viewLifecycleOwner, Observer {
when (it.status) {
Resource.Status.SUCCESS -> {
if (it.data?.success == "0") {
// Display error
Toast.makeText(requireContext(), it.data.message + "Registration", Toast.LENGTH_LONG).show()
} else if (it.data?.success == "1") {
// Go to home activity
Toast.makeText(requireContext(), it.data.message + "Registrationx", Toast.LENGTH_LONG).show()
val action = DetailsFragmentDirections.actionDetailsFragmentToHomeActivity()
navController.navigate(action)
}
}
Resource.Status.LOADING -> {
// Show loading
}
Resource.Status.ERROR -> {
Toast.makeText(requireContext(), it.toString(), Toast.LENGTH_LONG).show()
}
}
})
RESOURCE 类更新
data class Resource<out T>(val status: Status, val data: T?, val message: String?) {
enum class Status {
SUCCESS,
ERROR,
LOADING
}
companion object {
fun <T> success(data: T): Resource<T> {
return Resource(Status.SUCCESS, data, null)
}
fun <T> error(message: String, data: T? = null): Resource<T> {
return Resource(Status.ERROR, data, message)
}
fun <T> loading(data: T? = null): Resource<T> {
return Resource(Status.LOADING, data, null)
}
}
}
这是使用 POSTMAN 测试后的响应,它是正常工作的:
{"success":"1","message":"User details saved"}
UPDATE - 完整 LOGCAT
(这里是日志信息,包含了发送请求和响应的信息)
PHP 代码
(这里是 PHP 代码,用于处理 POST 请求并将数据存储到数据库)
英文:
I am trying to make a Post Request using Retrofit, MVVM, Coroutines and Hilt.
After sending the post request I get this error
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
(I have searched but none was helpful)
AppModule
@Provides
@Singleton
fun provideRetrofit(gson: Gson) : Retrofit = Retrofit.Builder()
.baseUrl(EndPoints.BASE_URL)
.client(OkHttpClient.Builder().also { client ->
if (BuildConfig.DEBUG){
val logging = HttpLoggingInterceptor()
logging.setLevel(HttpLoggingInterceptor.Level.BODY)
client.addInterceptor(logging)
}
}.build()
)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
@Provides
@Singleton
fun provideApiService(retrofit: Retrofit) = retrofit.create(ApiService::class.java)
ApiService
@POST(EndPoints.REGISTER_WITH_EMAIL)
suspend fun registerUserWithEmail(@Body newUser: NewUser) : Response<JsonResponse>
ApiDataSource
suspend fun createNewUserEmail(newUser: NewUser) = apiService.registerUserWithEmail(newUser)
NewUser
data class NewUser (
@SerializedName("username") val userName: String?,
@SerializedName("password") val password: String?,
@SerializedName("email") val email: String?,
@SerializedName("birthday") val birthday: String?,
@SerializedName("birth_year") val birthYear: String?,
@SerializedName("fullname") val fullname: String?,
@SerializedName("gender") val gender: String?)
RegisterRepo
suspend fun saveUserWithEmail(newUser: NewUser) = safeApiCall {
apiDataSource.createNewUserEmail(newUser) }
RegisterViewModel
//SaveUserDetails
private val _saveDetailsEmail = MutableLiveData<Resource<JsonResponse>>()
fun doRegisterUserEmail(newUser: NewUser) = viewModelScope.launch {
try {
_saveDetailsEmail.value = registerRepo.saveUserWithEmail(newUser)
}
catch (exception: Exception){
}
}
JsonResponse
data class JsonResponse (val success: String, val message: String)
RegisterFragment
val userDetails = NewUser(usernameString, passwordPassed, emailPassed, birthdayPassed, birthYearPassed, fullnameString, genderString)
registerViewModel.doRegisterUserEmail(userDetails)
registerViewModel.saveDetailsEmail.observe(viewLifecycleOwner, Observer {
when(it.status){
Resource.Status.SUCCESS -> {
if(it.data?.success == "0"){
//Display error
Toast.makeText(requireContext(), it.data.message + "Registration", Toast.LENGTH_LONG ).show()
}
else if(it.data?.success == "1"){
//go to home activity
Toast.makeText(requireContext(), it.data.message + "Registrationx", Toast.LENGTH_LONG ).show()
val action = DetailsFragmentDirections.actionDetailsFragmentToHomeActivity()
navController.navigate(action)
}
}
Resource.Status.LOADING -> {
//Show loading
}
Resource.Status.ERROR -> {
Toast.makeText(requireContext(), it.toString(), Toast.LENGTH_LONG).show()
}
}
})
}
This is the response after testing with POSTMAN. it was working
{"success":"1","message":"User details saved"}
Update RESOURCE class
data class Resource<out T>(val status: Status, val data: T?, val message: String?) {
enum class Status {
SUCCESS,
ERROR,
LOADING
}
companion object {
fun <T> success(data: T): Resource<T> {
return Resource(Status.SUCCESS, data, null)
}
fun <T> error(message: String, data: T? = null): Resource<T> {
return Resource(Status.ERROR, data, message)
}
fun <T> loading(data: T? = null): Resource<T> {
return Resource(Status.LOADING, data, null)
}
}
UPDATE - FULL LOGCAT
6:01.640 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: --> POST
https://2e3045dc760e.ngrok.io/snappmi/account/register/register_with_email.php
09-20 14:26:01.640 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: Content-Type: application/json
09-20 14:26:01.640 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: Content-Length: 150
09-20 14:26:01.640 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: {"birth_year":"1999","birthday":"1999-09-20","email":"makanaki@gmail.com","fullname":"makanaki","gender":"Male","password":"yellow","username":"maka"}
09-20 14:26:01.640 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: --> END POST (150-byte body)
09-20 14:26:01.660 20137-20137/com.snappmi.snappmi W/DisplayListCanvas: DisplayListCanvas is started on unbinded RenderNode (without mOwningView)
09-20 14:26:01.660 20137-20137/com.snappmi.snappmi W/DisplayListCanvas: DisplayListCanvas is started on unbinded RenderNode (without mOwningView)
09-20 14:26:08.140 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <-- 200 https://2e3045dc760e.ngrok.io/snappmi/account/register/register_with_email.php (6500ms)
09-20 14:26:08.140 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: content-type: text/html; charset=UTF-8
09-20 14:26:08.140 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: date: Sun, 20 Sep 2020 13:27:07 GMT
09-20 14:26:08.140 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: server: Apache/2.4.43 (Win64) OpenSSL/1.1.1g PHP/7.4.6
09-20 14:26:08.140 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: x-powered-by: PHP/7.4.6
09-20 14:26:08.140 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: content-length: 1475
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <b>Notice</b>: Undefined index: username in <b>C:\xampp\htdocs\snappmi\account\register\register_with_email.php</b> on line <b>7</b><br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <b>Notice</b>: Undefined index: password in <b>C:\xampp\htdocs\snappmi\account\register\register_with_email.php</b> on line <b>8</b><br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <b>Notice</b>: Undefined index: email in <b>C:\xampp\htdocs\snappmi\account\register\register_with_email.php</b> on line <b>9</b><br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <b>Notice</b>: Undefined index: birthday in <b>C:\xampp\htdocs\snappmi\account\register\register_with_email.php</b> on line <b>10</b><br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <b>Notice</b>: Undefined index: birth_year in <b>C:\xampp\htdocs\snappmi\account\register\register_with_email.php</b> on line <b>11</b><br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <b>Notice</b>: Undefined index: fullname in <b>C:\xampp\htdocs\snappmi\account\register\register_with_email.php</b> on line <b>12</b><br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <b>Notice</b>: Undefined index: gender in <b>C:\xampp\htdocs\snappmi\account\register\register_with_email.php</b> on line <b>13</b><br />
09-20 14:26:08.150 20137-20305/com.snappmi.snappmi I/okhttp.OkHttpClient: <br />
}
PHP SCODE
if ($_SERVER['REQUEST_METHOD']=='POST'){
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];
$birthday = $_POST['birthday'];
$birth_year = $_POST['birth_year'];
$fullname = $_POST['fullname'];
$gender = $_POST['gender'];
$joined = date('Y/m/d H:i:s');
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
if(usernameExists($conn, $username))
{
$result["success"] = "0";
$result["message"] = "Username already taken";
echo json_encode($result);
}
elseif(!usernameExists($conn, $username)){
$sql = "INSERT INTO users (username, password, email, birthday, birth_year, fullname, gender, joined) VALUES (?,?,?,?,?,?,?,?)";
$stmt= $conn->prepare($sql);
$stmt->execute([$username, $hashed_password, $email, $birthday, $birth_year, $fullname, $gender, $joined]);
if($stmt){
$result["success"] = "1";
$result["message"] = "success";
echo json_encode($result);
}
}
else{
$result["success"] = "0";
$result["message"] = "An error occured" .mysqli_error($conn);
echo json_encode($result);
}
}
答案1
得分: 1
我必须解码发送到服务器的 JSON 数据,特别是在这里内容类型为 application/json 时。
$data = file_get_contents('php://input');
$json_data = json_decode($data, true);
// 我在上面添加了这些
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$username = $json_data["username"];
$password = $json_data["password"];
$email = $json_data["email"];
}
英文:
I had to decode the JSON sent to the server especially when the content type here is application/json
$data = file_get_contents('php://input');
$json_data = json_decode($data , true);
//I added these above
if ($_SERVER['REQUEST_METHOD']=='POST'){
$username = $json_data["username"];
$password = $json_data["password"];
$email = $json_data["email"];
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论