简体   繁体   中英

Invalid Retrofit response for API call

I am trying a login to a server from Android using Retrofit 2. The API for login is working fine in postman (REST client tool) and getting the response like this

[
    {
        "success": true,
        "message": "Enjoy your token!",
        "token": "ABCDEFGHIJKLMNOPQESTUVWXYZ",
        "log_id": 1234
    }
]

But when I tried with the same flow in Android using Retrofit 2 I m getting different output. This is the log snippet for Android when I call Login API in android.

08-12 11:27:29.299 13457-13593/com.example.user.retrofit D/OkHttp: --> POST http://www.test.com/api/authenticate http/1.1
08-12 11:27:29.300 13457-13593/com.example.user.retrofit D/OkHttp: Content-Type: application/json; charset=UTF-8
    Content-Length: 181
    Accept: application/json
08-12 11:27:29.301 13457-13593/com.example.user.retrofit D/OkHttp: {"data":"VTJGc2RHVmtYMWdNYj1E"}
    --> END POST (181-byte body)
08-12 11:27:35.087 13457-13593/com.example.user.retrofit D/OkHttp: <-- 200  https://www.test.com/api/authenticate (5785ms)
    content-type: text/html
    cache-control: no-cache
    content-length: 210
    x-iinfo: 7-48850495-0 0NNN RT(1534053455965 0) q(0 -1 -1 5) r(0 -1) B10(4,289,0) U5
    set-cookie: visid_incap_1748743=CMWA4MwbTNGL5G0hHnAZBE/Mb1sAAAAAQUIPAAAAAADakNS0YTyMIvKXh6Zh0cjx; expires=Sun, 11 Aug 2019 09:31:38 GMT; path=/; Domain=.test.com
    set-cookie: incap_ses_705_1748743=z9lvBtlqCnHsdSffSqrICU/Mb1sAAAAAgZliHJa2lcppoIp0iVqtng==; path=/; Domain=.test.com
08-12 11:27:35.088 13457-13593/com.example.user.retrofit D/OkHttp: <html>
    <head>
    <META NAME="robots" CONTENT="noindex,nofollow">
    <script src="/_Incapsula_Resource?SWJIYLWA=5074a744e2e3d891814e9a2dace20bd4,719d34d31c8e3a6e6fffd425f7e032f3">
08-12 11:27:35.089 13457-13593/com.example.user.retrofit D/OkHttp: </script>
    <body>
    </body></html>
    <-- END HTTP (210-byte body)

Android Activity class for login is as below

package com.example.user.retrofit;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import java.io.IOException;
import java.security.cert.CertificateException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://www.test.com/api/")
                .addConverterFactory(GsonConverterFactory.create())
                .client(getUnsafeOkHttpClient().build())
                .build();
        LoginRequest login = new LoginRequest();
        login.setData("VTJGc2RHVmtYMWdNYj1E");
        GitHubService service = retrofit.create(GitHubService.class);
        service.login(login).enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    Log.d("OnResponse", response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

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

    }
    public static OkHttpClient.Builder getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            // add logging as last interceptor
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            builder.addInterceptor(logging);  // <-- this is the important line!
            return builder;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public interface GitHubService {
        @Headers({
                "Accept: application/json"
        })
        @POST("authenticate")
        Call<ResponseBody> login(@Body LoginRequest user);
    }

    private static class LoginRequest {
        private String data;


        public String getData() {
            return data;
        }

        public void setData(String data) {
            this.data = data;
        }
    }
}

Please anybody can tell me why I am getting HTML content when I tried from Android. What needs to be done to get the correct JSON response?

发送User-Agent:“您的应用名称”标头主体Alsoo

Thank you for the question, this problem is related to the server side framework like laravel php which protects unauthorized access and prevents from unknown client requests( in your case your retrofit is the client). It checks for the "User-Agent" header value, if not supplied captcha error is thrown ". This also happens when you avoid the "sessions cookies" sent by the server. Browser can handle and maintaining sessions cookies very easily but retrofit seems to have problem maintaining the sessions cookies by default.

1.Add a new interceptor to your okhttpClientBuilder

okhttpClientBuilder.addInterceptor(new Interceptor(){
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request original = chain.request();
                Response response;
                Request request = original.newBuilder()
                        .addHeader("User-Agent", System.getProperty("http.agent"))//important
                        .addHeader("Accept", "application/json")                      
                        .method(original.method(), original.body())
                        .build();
                request.headers().getAll("Cookie"));
                response= chain.proceed(request);
                response.headers().getAll("Set-Cookie"));
                return  response;
          }
     });

2.In your android studio-> build.gradle file(project level) , find below similar structure in the build.gradle file and add a maven repo like below

 allprojects {
    repositories {
    //other configs.....

    //add this if not present
    maven { url "https://jitpack.io" } 
     }
  }

3.Add the dependency in your build.gradle file (app level)

 dependencies {

   //other important dependency....

   //add this dependency for  handling cookies
   implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
 }
  1. Sync your project

  2. Add this below code after creating your okhttpClientBuilder

    CookieJar cookieJar1=new PersistentCookieJar(new SetCookieCache(),new SharedPrefsCookiePersistor(context)); okhttpClientBuilder.cookieJar(cookieJar1);//important okhttpClientBuilder.build();//returns OkHttpClient instance

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM