Retrofit gets 400 Bad request but works with postman

▼魔方 西西 提交于 2021-02-19 07:53:19

问题


My api base url is:

https://locodealapi.herokuapp.com/api/deals

In postman pass following in header and it works fine.

x-access-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX25hbWUiOiJkZWFsQWRtaW4iLCJ1c2VyX3Bhc3N3b3JkIjoiY2U5MDZkNDkzMWY3NmFhZWFmZTViNjM0YTg3Y2RkYzQ4YjMzNmUzYmVlZDU1N2ZhZTI0YzMxZTY3YmQyN2NhZDg4NDJmNzJlNTJlNGUyODc5ZWVkODY1MDljYzY5ODJlNDYwMjU0Mzk4ODQzMTljMTQxMGMwOTcxNGU0Y2MxMDNiMDQwYjkwOTQ1OTMyMjYwMGI1MjgwMmRkOTc2YTE4OGE5MTZiMWU4ZmU1YmY1ZWZiNTlkYjc2NDhmMjQxOTg0ODdiMWE5OGVhMjg2ZWZjZDI1M2Y5ZWUxNTQ0OTI3ODZiYjY3NzNmZTZjNGY3ODhmNzJjMzQ0NTEwMzg2NjkyNzIzMjNiMjZmYjFhMmUzYjE0ZTQ0Nzc0NzljMTExMzNkZjIwMmE3ODY2OGIxZjdiY2NlZjQ5NTM0YTJhYzk5N2Y0MTc0NzU2OTkwOTg5NjQ1YzljNWQxYTZkYmUyZTI1ZjFlNDE3YjdhYWI1N2QyZGJhNmVmOWEwNzk5N2Q5ZDcyNTgxMzUyYzc4Y2IxY2RiMDRmNDFkZjMwNzdjYzAxMGM2YmYzYWMzOTQ5OTJjN2Y3ZGVmYmE3YzllZWMxMzI5ODhlODBiM2RmYWE5NTVhMzE3NTgxNThiZjYxYjYyN2U4Y2UzOTg2NmRkODk2YzBlZDkzNDJlMzhiMzhkM2Q0ZTY0YWIzZWIwNGU4YmU5MGQwNmM2NTg2OWYyNzZkMzgyOTU3MTFkODgyNjI4NGIxMjkzYzQ0ZGNjMWM3ZjU2YmE4OGM5MTkyNDMzZWY0YTcwZGE2NTkzMzAwZmUzMGMxYjkwOWY5YmJjMDhmY2M5Zjk3NjUwYmJkOTVhNzExNWVlOGY3MjI5N2Q4ZGY4MjZiMTk0MTBlZjQ0OWZkMTQ1NTg3Nzc2NjUxZDI5OGMyYzMwMTZiMDMxMGEwZjRlMWQ4NzgwZTExYmVkOTZhYzg3MDU2YzIwYWU4ODZiYjI3NGZkNGVhZGMzMjQ0ZjlmMmZkMGIyMGMzZTAyZjI1NGQ3OWYzYzhiM2FmZGJiM2UzYTM1YTA2MjNjMTQwY2JmNzMxZWMxYjE2Y2VmNmIwY2RhMjQ1YjkzZmY4NzQ1MGRjNWFhZDE2MzdkNTQ5ZjM5ZDkwZjk5MWFiNWMxNTcwNWExYWJjYWQxYzQyYjNmMTViN2Y5N2I0YTc1ZDA2YTgwYjkwOWI0ZDJlZjRiNWE0NzdhMTMzYWI0ODkwMmIyNWFiM2VmYTMzNDdjMDcxODQ4NmMwYmU2NGQxYzUxMjA1ZTMwYjU5NjY3Yjk5ZTVlYTdkZWNiMWE4MWRkNjcyYzEwMzU5YmM2NGNlZWI3ZTEyOWJlYjZjYWUzYTM0ZjM0M2NiYjk4NyIsImNyZWF0ZXRpbWUiOm51bGwsImZpcnN0X25hbWUiOm51bGwsImxhc3RfbmFtZSI6bnVsbCwiYWdlIjpudWxsLCJzZXgiOm51bGwsImRvYiI6bnVsbCwic3RhdHVzIjpudWxsLCJpdGVyYXRpb24iOjEwMDAwLCJ1c2VyX3R5cGUiOiIwIiwidXNlcl9pbWFnZSI6bnVsbCwic2FsdCI6Ikh1dm9VQ3FRak81Mi9BbkJIdmp2MldEMERod2JmM0R4ZXV6ZWJMSlFYK3hZTUptMmRJSUw3VFYvcnFVVXFVNUpmRlY0dHhkMHNCcXhLbnVNakU2YlNzVnpaQ0dWVXg3YmY4MGNubTR5WnB5OElEUWowY1crTXhCUXdvMFNja2UzT0FnVk4zd2pnNmlxSVk3VnJwRmw1WTNLRzFwY1NMelZjREJiME9XdXdjcz0iLCJpYXQiOjE1MTAxMjY1OTUsImV4cCI6MTUxODc2NjU5NX0.5XFJnJqTsfID9uqOwkNf46oraj9jDxic7qNSqBdunD0

In retrofit Interface I have following but get 400 Bad request

@POST("api/deals")
    Call<ResponseBody> deals(@Header("x-access-token") String x_access_token)

Calling code:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://locodealapi.herokuapp.com")
                .addConverterFactory(GsonConverterFactory.create())
                .client(httpClient.build())
                .build();
        AppRestAPI client = retrofit.create(AppRestAPI.class);    

        Call<ResponseBody> call1 = client.deals(
                token
        );          

        call1.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                Log.i(TAG, "The response is " + response.message());
                Log.i(TAG, "The response is " + response.body());    

                try {
                    Log.i(TAG, "The response is " + response.errorBody().string());

                    if (response.code() == 400) {
                        Log.v("Error code 400",response.errorBody().string());
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }    
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e(TAG, "onFailure: Failed", t);

            }
        });

OKHTTP Log interceptor

11-21 21:14:30.939 3253-3342/? D/OkHttp: --> POST https://locodealapi.herokuapp.com/api/deals
11-21 21:14:30.939 3253-3342/? D/OkHttp: Content-Length: 0
11-21 21:14:30.940 3253-3342/? D/OkHttp: x-access-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoyNSwidXNlcl9uYW1lIj....
11-21 21:14:30.942 3253-3342/? D/OkHttp: --> END POST (0-byte body)    
11-21 21:14:34.188 3253-3342/? D/OkHttp: <-- 400 Bad Request https://locodealapi.herokuapp.com/api/deals (3246ms)
11-21 21:14:34.189 3253-3342/? D/OkHttp: Connection: close
11-21 21:14:34.189 3253-3342/? D/OkHttp: Server: Cowboy
11-21 21:14:34.189 3253-3342/? D/OkHttp: Date: Tue, 21 Nov 2017 15:29:33 GMT
11-21 21:14:34.190 3253-3342/? D/OkHttp: Content-Length: 0
11-21 21:14:34.191 3253-3342/? D/OkHttp: <-- END HTTP (0-byte body)
11-21 21:14:34.196 3253-3253/? I/BaseDrawerActivity: The response is Bad Request
11-21 21:14:34.196 3253-3253/? I/BaseDrawerActivity: The response is null
11-21 21:14:34.196 3253-3253/? I/BaseDrawerActivity: The response is 

Note: The same code works fine in local nodejs server (http only)


回答1:


1.Frist thing your api is a GET Method so use @GET instead @POST

Second try to change url base url in retrofit .baseUrl("https://locodealapi.herokuapp.com") to .baseUrl("https://locodealapi.herokuapp.com/") this will work. or leave your problem in comment 2.this is sample code

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(
            new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException{
                 Request original = chain.request();
                    // Request customization: add request headers
                    Request.Builder requestBuilder =original.newBuilder().
                            method(original.method(), original.body());
                    Request request = requestBuilder.build();
                    return chain.proceed(request);
                }
            })
            .addInterceptor(interceptor).connectTimeout(60,TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).build();

    Retrofit retrofit = new Retrofit.Builder().baseUrl("https://locodealapi.herokuapp.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient).build();
    UserApi userApi = retrofit.create(UserApi.class);
    Call<ResponseBody> call = userApi.deals("your token");
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call,retrofit2.Response<ResponseBody> response) {
        }
        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {}
    });
}

@GET("api/deals") Call deals(@Header("x-access-token") String x_access_token);




回答2:


Greeting of the day!

Try this:

@FormUrlEncoded
@POST("/api/deals")
    Call<ResponseBody> deals(@Header("x-access-token") String x_access_token, @Field("<parameter_name>") String parameter);

Call api as below:

 Call<ResponseBody> call = client.deals(token,"<parameter>");

Here, i am assuming that the API has a parameter which can be passed as 2nd argument in the method deals(). You can pass multiple parameters as the arguments of the method.

Refer the following link for more details: https://futurestud.io/tutorials/retrofit-send-data-form-urlencoded

I hope, this solves your problem. If not, please provide complete details of the API that you want to call.




回答3:


A 400 response means that it's a disagreement between your request and the server, but that the request was created, sent, and a response was parsed. Which means Retrofit is working fine. You can use OkHttp's logging interceptor to log the raw request and compare it with what the server expects.

Also your Response size is around 5.96 MB. This is too big response. Instead of receiving this much of data in single response you could implement pagination or something similar to break down data. This could be one of the reason.




回答4:


//Your Main connection Class

public class ApiClient {
public static final int DEFAULT_TIMEOUT_SEC = 90;
public static OkHttpClient client;
private static Retrofit retrofit = null;

public static Retrofit getClient() {

    OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
            .connectTimeout(DEFAULT_TIMEOUT_SEC, TimeUnit.SECONDS)
            .readTimeout(DEFAULT_TIMEOUT_SEC, TimeUnit.SECONDS)
            .writeTimeout(DEFAULT_TIMEOUT_SEC, TimeUnit.SECONDS);

    httpClient.addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Request original = chain.request();
            System.out.println("API_KEY"+PrefManager.getActiveInstance(RecrouteCandidateApplication.getsCurrentContext()).getDeviceToken());
            Request request = original.newBuilder()
                    .header("x-access-token",YOUR_ACCESS_TOKEN"")
                    .method(original.method(), original.body())
                    .build();

            return chain.proceed(request);
        }
    });

   //For logging the call on Logcat
    HttpLoggingInterceptor interceptor1 = new HttpLoggingInterceptor();
    interceptor1.setLevel(HttpLoggingInterceptor.Level.BODY);
    httpClient.addInterceptor(interceptor1);
    client = httpClient.build();

    if (retrofit == null) {
        retrofit = new Retrofit.Builder()
                .baseUrl(AppConstants.BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }
    return retrofit;
}

Use in Your Class which will initiate the connection like this

ApiInterface apiService =
                ApiClient.getClient().create(ApiInterface.class);

And This will be your ApiInterface

public interface ApiInterface {

@POST("Your url here")
Call<JsonObject> sampleMethod();
/*For non-empty body use this*/
//Call<JsonObject> getSignUpResponse(@Body JsonObject register);

//For form data use this
@FormUrlEncoded
@POST("Your url here")
Call<String> sampleMethod1(@Field(value= "param1_key", encoded = true) String param1_value);

 }

Make a call like this for json

JsonObject obj= new JsonObject();
obj.addProperty("key1","keyvalue");

Call<JsonObject> call = apiService.sample1(obj);
                            call.enqueue(new Callback<JsonObject>() {
                                @Override
                                public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
                                    if (response.body().get("status").getAsString().equals("1")) {
                                        Toast.makeText(context, response.body().get("msg").getAsString(), Toast.LENGTH_LONG).show();
                                    } else {
                                        Toast.makeText(context, response.body().get("msg").getAsString(), Toast.LENGTH_LONG).show();
                                    }
                                }

                                @Override
                                public void onFailure(Call<JsonObject> call, Throwable t) {
                                    Toast.makeText(context, AppConstants.NO_DATA_AVAILABLE, Toast.LENGTH_LONG).show();
                                }
                            });



回答5:


for me the problem was because I had this line in the Gson builder :

 .excludeFieldsWithoutExposeAnnotation()

with the above line, all the fields in your model classes that you send as body in retrofit will be ignored if they are not annotated with the @Exposed annotation. removing .excludeFieldsWithoutExposeAnnotation() solved the problem for me.



来源:https://stackoverflow.com/questions/47375322/retrofit-gets-400-bad-request-but-works-with-postman

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!