预期 BEGIN_OBJECT 但在第 1 行第 1 列路径为 STRING - Laravel 到改造 2

Posted

技术标签:

【中文标题】预期 BEGIN_OBJECT 但在第 1 行第 1 列路径为 STRING - Laravel 到改造 2【英文标题】:Expected BEGIN_OBJECT but was STRING at line 1 column 1 path - Laravel to Retrofit 2 【发布时间】:2019-07-27 00:00:49 【问题描述】:

我使用 Laravel 构建了一个简单的 API,它运行良好。 我的 android 应用应该使用来自这个 API 的数据,但是对于一些 JSON 响应,我收到了一个错误

预期为 BEGIN_OBJECT,但在第 1 行第 1 列路径为 STRING

在收到此错误之前,错误是以下错误:

使用 JsonReader.setLenient(true) 在第 1 行第 1 列路径接受格式错误的 JSON

那我setLenient(true)来解决。

我在许多其他帖子中看到问题是 JSON 格式错误,但看起来一切都很好。

出现错误的 JSON 响应:


    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImRhMWUxNzU4YmI1YTFjMjAzZDI1MDk5OTM4YTljMjgwNDUyMjYzMDFhNjZiZmViZmJlMTQyY2FmNGU4OGUwMzc2NTZkN2RmZjI4NDUxMTEzIn0.eyJhdWQiOiIxIiwianRpIjoiZGExZTE3NThiYjVhMWMyMDNkMjUwOTk5MzhhOWMyODA0NTIyNjMwMWE2NmJmZWJmYmUxNDJjYWY0ZTg4ZTAzNzY1NmQ3ZGZmMjg0NTExMTMiLCJpYXQiOjE1NTE3OTIzMzAsIm5iZiI6MTU1MTc5MjMzMCwiZXhwIjoxNTgzNDE0NzMwLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.bi4l9mpUDLoYMLWwd1JyCAfoN2GtwpnpEmGnzsoDoIP_rcTWfT9IsixX4iwtbjSdOTBFkqSD9oGz8KncI24spgnKhofZelClSP6tNtI6P8q2b_PmnefytmNfu_fWBAvSTD2Tia8-cMCu_eF9QfNoOv_9JCYAaY__DY2W_zI3u8uLv25EZQPgBiW7MIT_gm9ZnD6JJlCL4rkgUuhdDG8lkjHCryAYVBqXsGLizl6YdgBp8zMYzONzjxT4nhTARL_aywE9ejZCt5Mkh5qvoGms4zkMMAW0OIYVP_puB7MSPJAriCR1kaBO06MSNGcfAdorn5VDpfwFV8t25mftOeaM1x8IvWT1K0_Hi0BtdV2twtJ-_uHcmIn8QiF3Tc6On7YWWWGEfJw0vAGqK5RaYtWVSo5iWbAiD5rsmCQRQDsg4GnEH9AnYHjcjortBe01YuimQ4TMSIgWLpRfExwcPgQkonklWqODcE8nvuWzyKUirmm56gGj1wBZciqrYsDRTImP4Ntv1Q5Tb3r2PoFlqxfn3_qux1OQpTyzHGEOEaE9ZQnNoELjwGd5nUuFOYCOdwafIUsG0atHtoPBj_S6jTsJJdIWqQzCexchpkwBUgP5i6o1QCai7BcOnTXKJ3V6kV17SGtiP7gqTM9fvESD0BIuK4Xd0dsA8mc67_HwLJyhpXM",
    "token_type": "Bearer",
    "expires_at": "2019-03-19"

有效的 JSON 响应:


    "message": "The given data was invalid.",
    "errors": 
        "username": [
            "The username has already been taken."
        ]
    

我用JSONLint 测试过 JSON,它说 JSON 很好

不工作 - Laravel JSON 响应

return response()->json([
       'access_token' => $tokenResult->accessToken,
        'token_type' => 'Bearer',
        'expires_at' => Carbon::parse(
            $tokenResult->token->expires_at
        )->toDateString()
        ], 200);

工作 - Laravel JSON 响应

    return response()->json([
        'message'=>'Cadastro realizado.',
        'user_id' => $user->id
    ], 201);

Android - 登录

btnSignin.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            Log.d(TAG, "onClick: " + etSigninUser.getText().toString());
            Log.d(TAG, "onClick: " + etSigninPassword.getText().toString());
            Call<LoginResponse> call = apiService.userLogin(
                    etSigninUser.getText().toString(),
                    etSigninPassword.getText().toString(),
                    false
            );

            call.enqueue(new Callback<LoginResponse>() 
                @Override
                public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) 
                    Log.d(TAG, "onResponse: " + response.code());
                

                @Override
                public void onFailure(Call<LoginResponse> call, Throwable t) 
                    Log.d(TAG, "onFailure: " + t.toString() + " " + t.getCause());
                    Log.d(TAG, "onFailure: " + t.toString());
                
            );
        
    );

Android - 登录响应模型

    public class LoginResponse 

    @SerializedName("access_token")
    @Expose
    private String accessToken;
    @SerializedName("token_type")
    @Expose
    private String tokenType;
    @SerializedName("expires_at")
    @Expose
    private String expiresAt;

    public String getAccessToken() 
        return accessToken;
    

    public void setAccessToken(String accessToken) 
        this.accessToken = accessToken;
    

    public String getTokenType() 
        return tokenType;
    

    public void setTokenType(String tokenType) 
        this.tokenType = tokenType;
    

    public String getExpiresAt() 
        return expiresAt;
    

    public void setExpiresAt(String expiresAt) 
        this.expiresAt = expiresAt;
    

**Android - Retrofit 2 调用 **

@FormUrlEncoded
@POST("auth/login")
Call<LoginResponse> userLogin(
        @Field("username") String username,
        @Field("password") String password,
        @Field("remember_me") boolean remember_me
);

我看不出我的代码有什么问题,一切似乎都很好,为什么会出现这个错误? JSON 格式是否错误?

编辑 1 - 邮递员

【问题讨论】:

你在邮递员中测试过吗? 是的,它在邮递员中工作正常。 检查,邮递员是否返回 200 OK? @KishoreJethava 看到我的编辑 无法指出任何问题。奇怪的是看到错误。 【参考方案1】:

我遇到了这个问题,我花了很多时间才弄清楚。

我在这里找到了解决方案:https://***.com/a/56903479/3971619

TLDR:用于创建 Retrofit 对象的 BASE_URL 变量在 / 之后不应有任何内容

替换:

val authApiService = Retrofit.Builder()
    .baseUrl("https://test.com/api/test") //There is path after the /
    .addConverterFactory(GsonConverterFactory.create(gson))
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build().create(AuthService::class.java)

val authApiService = Retrofit.Builder()
    .baseUrl("https://test.com/") //It should only be the base url without a path
    .addConverterFactory(GsonConverterFactory.create(gson))
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build().create(ServiceClass::class.java)

【讨论】:

以上是关于预期 BEGIN_OBJECT 但在第 1 行第 1 列路径为 STRING - Laravel 到改造 2的主要内容,如果未能解决你的问题,请参考以下文章

预期 BEGIN_OBJECT 但在第 1 行第 1 列路径为 STRING - Laravel 到改造 2

预期 BEGIN_ARRAY 但在第 1 行第 2 列是 BEGIN_OBJECT。如何解决?

获得错误预期BEGIN_ARRAY但在第1行第2列路径$是BEGIN_OBJECT

改造后请求错误 - java.lang.IllegalStateException: 预期 BEGIN_OBJECT 但在第 1 行第 1 列路径 $

AsyncTask 预期为 BEGIN_OBJECT,但在第 1 行第 2 列路径 $ 处为 BEGIN_ARRAY

预期为 BEGIN_ARRAY,但在第 1 行第 2 列改造时为 BEGIN_OBJECT2