我使用 Retrofit2 调用了 PATCH Web 服务,但未调用 onResponse,而是调用了 onFailure 尽管服务的操作在服务器端成功了 完美
每当我尝试使用 fiddler 检查服务的工作情况时,我发现问题是序列化服务的即将到来的响应,并且当使用 fiddler 时,我发现 JSON 响应没有内容,因此 Retrofit 服务假设其失败因为没有内容并且无法序列化 EMPTY 内容 并给我这个错误
java.io.EOFException: End of input at line 1 column 1
Fiddler 原始响应
HTTP/1.1 200 OK
Server: nginx/1.9.4
Date: Wed, 02 Mar 2016 09:55:55 GMT
Content-Type: application/json
Content-Length: 0
Connection: close
Status: 200 OK
X-Content-Type-Options: nosniff
Fiddler Json 响应为空
java 中的网络服务
Call<Object> call = TimeCapp.services.accept_invited_alerts(HomeActivity.api_token, alert_id);
call.enqueue(new Callback<Object>()
{
@Override
public void onResponse (Call<Object> call, Response<Object> response)
{
if (response.isSuccess()) {
String x = response.body();
}
}
@Override
public void onFailure (Call<Object>call, Throwable t)
{
String x = t.getMessage();//java.io.EOFException: End of input at line 1 column 1
}
}
我尝试用 String、JsonObject、emptyCalssBody 替换 object .... 但失败了
网络服务接口
@PATCH("alerts/{alert_id}/accept")
Call<Object> accept_invited_alerts(@Header("X-Api-Token") String
api_token, @Path("alert_id") int alert_id);
如果主体为空,则返回 void
@PATCH("alerts/{alert_id}/accept") Call<Void> accept_invited_alerts(@Header("X-Api-Token") String api_token, @Path("alert_id") int alert_id);
对于 Rx java 的改造,你可以使用这样的东西
@PATCH("alerts/{alert_id}/accept") Observable<Response<Void>> accept_invited_alerts(@Header("X-Api-Token") String api_token, @Path("alert_id") int alert_id);
编辑:对于 kotlin
@PATCH("alerts/{alert_id}/accept")
fun accept_invited_alerts(@Header("X-Api-Token") api_token: String, @Path("alert_id") alert_id: Int): Call<Unit>
和
@PATCH("alerts/{alert_id}/accept")
fun accept_invited_alerts(@Header("X-Api-Token") api_token: String, @Path("alert_id") alert_id: Int): Observable<Response<Unit>>
您可以创建 NullOnEmptyConverterFactory.class :
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
public class NullOnEmptyConverterFactory extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
return new Converter<ResponseBody, Object>() {
@Override
public Object convert(ResponseBody body) throws IOException {
if (body.contentLength() == 0) return null;
return delegate.convert(body);
}
};
}
}
并添加到代码创建中。例如:
UploadImageNghiemThuApi uploadService = new Retrofit.Builder()
.baseUrl(Config.URL+"/")
.client(okHttpClient)
// -----add here-------
.addConverterFactory(new NullOnEmptyConverterFactory())
//---------------------
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(UploadImageNghiemThuApi.class);
希望它可以帮助您解决问题。 谢谢!
编辑!!!
对于 kotlin 用例,你可以检查这个
class NullOnEmptyConverterFactory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *> {
val delegate: Converter<ResponseBody, *> =
retrofit.nextResponseBodyConverter<Any>(this, type, annotations)
return Converter { body -> if (body.contentLength() == 0L) null else delegate.convert(body) }
}
}
非常感谢。
API
@FormUrlEncoded
@POST("/rebu/insertusuario.php")
Call<Void> insertLogin(
@Field("email") String email,
@Field("senha") String senha,
@Field("codCondutor") Long codCondutor
);
班级:
Call call = service.insertLogin(login.getEmail(), login.getSenha(), login.getCodCondutor());
对于我来说,在 Laravel 中,我在功能完成后没有发送任何响应,只需在服务器端添加以下行有所帮助。这可以适应您正在使用的语言。 只需从服务器端发送一些响应即可。
use Response;
return Response::json(array(
'result' => 'success',
));
我在 Spring Boot 服务中遇到了类似的问题。 问题在于 Content-Length 标头值。超过指定字节数的任何内容都会导致问题。
删除标题后,问题得到解决。
您可以删除标题或尝试使用一个很大的值。
解决这种(Retrofit2 error java.io.EOFException: End of input at line 1 column 1)异常,即空体异常。你需要穿越虚空。
private void callCheck(){
Api api = service.getTestClient().create(Api.class);
Call<Void> call = api.SendRequest(Constant.client_id,Constant.client_secret,Constant.apiUserName);;
call.enqueue(new Callback<Void>() {
@Override
public void onResponse(Call<Void> call, retrofit2.Response<Void> response) {
if (response.isSuccessful()) {
//Perform according to it...
// Here I am getting the response from the header...
} else {
// Is to handle the error body if an user provided the wrong values in the header...
try {
//these are for the error body
JSONObject jsonObject =new JSONObject(response.errorBody().string());
Log.d("ErrorBody:", jsonObject.toString());
JSONObject responseObj = jsonObject.getJSONObject("fault");
String fault = responseObj.getString("faultstring");
Log.d(TAG, "Fault: " + fault);
JSONObject responseObjDetail = responseObj.getJSONObject("detail");
String detail = responseObjDetail.getString("errorcode");
Log.d(TAG, "Detail: " + detail);
}catch (JSONException | IOException e) {e.printStackTrace();}
}
}
如果您尝试使用 Retrofit Result 类(如
Single<Result<Void>>
中所示),但您的代码可能错误地使用了 kotlin.Result 类,而不是使用 Retrofit2.adapter.rxjava2.Result 类,则在 Kotlin 中可能会发生此错误。
如果这是问题所在,请添加导入行
import retrofit2.adapter.rxjava2.Result
,以便您的代码将为结果使用正确的类。
I have been facing the same issue for such days and I checked this solution -
You can get this error when you are expecting an object in the response, but the API doesn't return anything other than result codes (200,...). Options: - Check that the API returns a ServerResponse. - If you don't need it to return anything, use Observable<Response<Void>> instead of Observable<ServerResponse>
this is my old working face with this issue Log : AddTaskError - End of input at line 1 column 1 -
@POST("/Api/AddUpdateTask")
fun addUpdateTask(
@Header("Content-Type") contentType: String?,
@Header("SessionId") session: String?,
@Body requestBody: RequestBody
): Call<JsonObject>
and this is my method -
private fun addTaskApi() {
try {
customProgress?.show("")
} catch (e: BadTokenException) {
e.printStackTrace()
}
val showObserId = JSONArray().apply {
if (!observerid.isNullOrEmpty()) {
observerid!!.split(",").forEach {
put(it)
}
}
}
val showUserId = JSONArray().apply {
if (!assignId.isNullOrEmpty()) {
assignId!!.split(",").forEach {
put(it)
}
}
}
if (!Utils.isNetworkAvailable(this@AddTask)) {
Toast.makeText(applicationContext, "Internet not available", Toast.LENGTH_LONG).show()
} else {
try {
val apiClient = RetroApi.client?.create(APIClient::class.java) ?: return
val postdata = JSONObject().apply {
put("TaskId", 0)
put("TaskLeadId", chooseLeadId)
put("TaskTitle", etTaskName!!.text.toString())
put("TaskDescription", Html.toHtml(etTaskDescription!!.text))
put("TaskCreatedBy", 0)
put("TaskAssignTo", showUserId)
put("TaskObserver", showObserId)
put("TaskStartDate", tvStartdate!!.text.toString())
put("TaskEndDate", tvEndDate!!.text.toString())
put("TaskCreatedDate", tvStartdate!!.text.toString())
put("TaskModifiedDate", tvStartdate!!.text.toString())
put("TaskStatus", 0)
put("IsTaskActive", activeValue)
put("IsDeleted", isDeleted)
put("TaskCompanyId", 0)
put("TaskPriority", leadPriorityId)
}
Log.d("request_edit_addtask", postdata.toString())
val requestBody =
postdata.toString().toRequestBody("application/json".toMediaTypeOrNull())
val call = apiClient.addUpdateTask(
"application/json",
sharedManager!!.sessionID,
requestBody
)
call.enqueue(object : Callback<JsonObject> {
override fun onResponse(
call: Call<JsonObject>,
response: Response<JsonObject>
) {
customProgress?.hide()
if (response.isSuccessful) {
val responseBody = response.body()
Log.d(
"addTaskApiResponseBody",
responseBody?.toString() ?: "Empty response body"
)
if (responseBody != null) {
processResponseAddTask()
} else {
Log.e("Error", "Empty or null response body")
runOnUiThread {
Toast.makeText(
this@AddTask,
"Empty or null response body",
Toast.LENGTH_SHORT
).show()
}
}
} else {
val errorBody = response.errorBody()?.string()
Log.e("Error_Response", errorBody ?: "Empty error response body")
if (response.code() == 401) {
Toast.makeText(
this@AddTask,
"Unauthorized request",
Toast.LENGTH_SHORT
).show()
LogOutApi(this@AddTask)
} else {
runOnUiThread {
Toast.makeText(
this@AddTask,
"Error: ${response.message()}",
Toast.LENGTH_SHORT
).show()
}
}
}
}
override fun onFailure(call: Call<JsonObject>, t: Throwable) {
customProgress?.hide()
t.printStackTrace()
Log.e("AddTaskError", "API call failed: ${t.message}")
}
})
} catch (e: Exception) {
e.printStackTrace()
}
}
}
Solution is -
@POST("/Api/AddUpdateTask")
fun addUpdateTask(
@Header("Content-Type") contentType: String?,
@Header("SessionId") session: String?,
@Body requestBody: RequestBody
): Call<Void> //Change this
and this part -
call.enqueue(object : Callback<Void> {
override fun onResponse(call: Call<Void>, response: Response<Void>) {
customProgress?.hide()
if (response.isSuccessful) {
Log.d("SuccessfulResponse", "Response body: ${response.body()?.toString()}")
Log.d("SuccessfulResponse", "Response code: ${response.code()}")
processResponseAddTask()
} else {
val errorCode = response.code()
Log.e("AddTaskErrorResponse", "API call failed with error code: $errorCode")
val errorBody = response.errorBody()?.string()
Log.e("Error_Response", errorBody ?: "Empty error response body")
runOnUiThread {
Toast.makeText(
this@AddTask,
"Error: ${response.message()}",
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onFailure(call: Call<Void>, t: Throwable) {
customProgress?.hide()
t.printStackTrace()
Log.e("AddTaskError", "API call failed: ${t.message}")
}
})
for me its working fine.