How to use http/2 with Okhttp on Android devices? - android

I'M testing a site that supports HTTP/2,like this,
and I try to use okhttp to send the request:
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url("https://www.google.it")
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Response response) throws IOException {
Log.d("TestHttp", "OkHttp-Selected-Protocol: " + response.header("OkHttp-Selected-Protocol"));
Log.d("TestHttp", "Response code is " + response.code());
}
});
In the log I got something like this:
OkHttp-Selected-Protocol: http/1.1
The okhttpClient chose to use http/1.1, how can I force it to use HTTP/2?

Okhttp 2.5+ only support http/2 above 5.0+ via ALPN.
but you can modify the source code to support http/2 above 4.0+ via NPN.

You just need to initialize your OkHttpClient in proper way.
Kotlin:
val client = OkHttpClient().newBuilder()
.protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1))
.build()
// Your client will now try to use HTTP 2 if possible. If not, then HTTP 1.1 will be used.
Java:
List<Protocol> protocols = new ArrayList<Protocol>();
protocols.add(Protocol.HTTP_2);
protocols.add(Protocol.HTTP_1_1);
OkHttpClient client = new OkHttpClient.Builder()
.protocols(protocols)
.build();
// Your client will now try to use HTTP 2 if possible. If not, then HTTP 1.1 will be used.
If you wish to check if HTTP 2 is being used, see my other answer: https://stackoverflow.com/a/72983159/1735603

Related

Making GET Request after a POST Request in the same Session with OkHttp in Android Studio

I am trying to retrieve some JSON data using OkHttp in Android Studio from the URL: www.duolingo.com/vocabulary/overview
Before I can get the data using this URL, it requires me to Login into the Duolingo server first (which makes sense since I want it to return data from my profile) so I make a POST request with my credentials using OkHttp. This is my code to achieve that:
OkHttpClient client = new OkHttpClient();
String postUrl = "https://www.duolingo.com/2017-06-30/login?fields=";
String getUrl = "https://www.duolingo.com/vocabulary/overview";
String credentials = "{\"identifier\": \"something#email.com\", \"password\": \"Password\"}";
RequestBody body = RequestBody.create(credentials, MediaType.parse("application/json; charset=utf-8"));
Request request = new Request.Builder()
.url(postUrl)
.post(body)
.build();
client.newCall(request).enqueue(new Callback()
{
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e)
{
Log.i("TAG", "ERROR - " + e.getMessage());
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException
{
if (response.isSuccessful())
{
Log.i("LOG", "LOGGED IN");
}
else
{
Log.i("LOG", "FAILED - " + response.toString());
}
}
});
The Response is successful and I get a 200 Response Code.
Now since I have Logged In, I want to make a GET Request to the URL mentioned above to get the JSON Data. Problem is I do not know how to make a GET Request in succession to the POST Request I just made. OkHttp treats the 2 consecutive requests as separate while I want them to be treated as the same session.
Someone told me Cookies can help but I am totally oblivious to that and how they work. All help is appreciated!

Adding fields to URL using Retrofit

I am building an Android APP where I use the Internet Game Database API through Mashape market place. I am using Retrofit for the get requests and getting data from the API requires an API key.
I got it to work but the API only return game ids and I want the game names and other information, but I am not sure how to add the fields. This is how Mashape query it:
HttpResponse<String> response = Unirest.get("https://igdbcom-internet-game-database-v1.p.mashape.com/games/?fields=name%2Crelease_dates")
.header("X-Mashape-Key", "API KEY HERE")
.header("Accept", "application/json")
.asString();
and this is my Retrofit Interface
public interface GamesAPIService {
#GET("/games/")
Call<List<GamesResponse>> gameList(#Query("mashape-key") String apikey);
}
I tried to use this
#GET("/games/?fields=name,release_dates")
But no luck, I also tried with #Field but didn't work either. Any ideas? Thanks.
Edit: Just to clarify when I add the "?fields=name,release_dates" I get 401 Unauthorized Error.
Firstly I think you need to add mashape key to all your request.
OkHttpClient httpClient = new OkHttpClient();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("X-Mashape-Key", "API_KEY_HERE")
.addHeader("Accept", "application/json")
.build();
return chain.proceed(request);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://igdbcom-internet-game-database-v1.p.mashape.com")
.client(httpClient)
.build();
And then this is information query.
public interface GamesAPIService {
#GET("/games")
Call<List<GamesResponse>> gameList(#Query("fields") String value);
}
And last thing for calling.
GamesAPIService gamesAPIService = retrofit.create(GamesAPIService.class);
Call<List<GamesResponse>> call = gamesAPIService.gameList("name,release_dates");
if (call!=null){
call.enqueue(new Callback<List<GamesResponse>>() {
#Override
public void onResponse(Call<List<GamesResponse>> call, Response<List<GamesResponse>> response) {
// handle success
}
#Override
public void onFailure(Throwable t) {
// handle failure
}
});
}

OAuth issue of request from Android app with Retrofit & Fabric

I am developing Android App interacting with Twitter using Fabric and Retrofit2 libraries. I want to display search timeline. My request URL is like this: https://api.twitter.com/1.1/friends/list.json?screen_name=xxx
The response body I got is null but I got the alert of bad authentication:215 and http error 400 in the debug mode.This is probably caused by invalid authentication of the request from my app.
The Twitter developer document said requests need to be authorized with OAuth and SSL certificated.
As for the OAuth issue, I wrote the request header based on the official document of twitter developer platform https://dev.twitter.com/oauth/overview/authorizing-requests
and create the header with okhttpclient and pass it to retrofit object.
The code for OAuth issue is like this.
public class TwitterClientApiClient extends TwitterApiClient {
private static final String TAG=TwitterClientApiClient.class.getSimpleName();
private static final MainApplication app=MainApplication.getInstance();
public static final String BASE_URL = "https://api.twitter.com/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
final String authStr = app.authStr();
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Accept", "application/json")
.header("Authorization", authStr)
.method(original.method(), original.body())
.build();
Headers okHeaders = request.headers();
Log.d(TAG,okHeaders.toString());
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
return retrofit;
}
public TwitterClientApiClient(TwitterSession session) {
super(session);
}
public FriendsService getFriendsService() {return getService(FriendsService.class);}
}
interface FriendsService {
#GET("/1.1/friends/list.json")
Call<FriendsResult> list(#Query("screen_name") String screen_name);
}
The following is the code making the request.
FriendsService apiService =
TwitterClientApiClient.getClient().create(FriendsService.class);
Call<FriendsResult> call = apiService.list(screenName);
Log.d(TAG, call.request().url().toString());
call.enqueue(new Callback<FriendsResult>() {
#Override
public void onResponse(Call<FriendsResult> call, Response<FriendsResult> response) {
//List<User> friends = response.body().getUsers();
Log.d(TAG,response.body().toString());
//Log.d(TAG, "Number of Friends: " + friends.size());
//String q = getQueryStr(friends);
//showSearchedTimeline(q);
}
#Override
public void onFailure(Call<FriendsResult>call, Throwable t) {
Log.e(TAG, t.toString());
}
});
However,according to https://oauth.net/core/1.0/#encoding_parameters
OAuth Authentication is done in three steps:
1.The Consumer obtains an unauthorized Request Token.
2.The User authorizes the Request Token.
3.The Consumer exchanges the Request Token for an Access Token.
My code which is based on references from the internet seems to do only Step 3 and thus the authentication is not complete. I wonder how to complete the whole authentication process of OAuth.
Also do I need to do sth in my code for SSL stuff?
Besides OAuth and SSL, any other security issue for request to twitter server I have overlooked?
Thanks in advance!
.header("Authorization", authStr)
Try with addHeader. You can activate the logs (useful to debug sometimes) using a logging interceptor. Ask the logger to show your headers, to see if that could be the problem. Available levels are here.

How to get headers from all responses using retrofit

I'm using Retrofit library version 2 with OkHttpClient.
I want to get some header from all responses.
I found one solution with OkClient:
public class InterceptingOkClient extends OkClient{
public InterceptingOkClient()
{
}
public InterceptingOkClient(OkHttpClient client)
{
super(client);
}
#Override
public Response execute(Request request) throws IOException
{
Response response = super.execute(request);
for (Header header : response.getHeaders())
{
// do something with header
}
return response;
}
}
But how i can do this if i'm using OkHttpClient?
Yes, this is old question.. but still found to answer because myself too was searching similar one.
okHttpClient.interceptors().add(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", "auth-value"); // <-- this is the important line, to add new header - replaces value with same header name.
Request request = requestBuilder.build();
Response response = chain.proceed(request);
Headers allHeaders = response.headers();
String headerValue = allHeaders.get("headerName");
return response;
}
});
Hope, this helps!
P.S: no error handled.
You can use the logging interceptor for that. Add it as an interceptor to your OkHttpClient builder while building the client, set the log level and voila! You will have all the information regarding the request as well as the response.
Here's how you can add the interceptor -
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpBuilder.addInterceptor(loggingInterceptor);
client = okHttpBuilder.build();
There are four options when it comes to what you want to Log - NONE,BASIC,HEADERS, and BODY.
Now build the the retrofit instance with the above defined client and you will have all the data you need.

Opening the connection using okhttp

I'm trying to Open the connection using okhttp.
something like,
urlConnection = client.open(url);
does not work with the new ok-http.jar file.
It was working with 1.5.x of okhttp version
Any suggestions?
Thanks
Code from documentation
public static void main(String[] args) throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://kenumir.pl/")
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
}
Method execute is the key ;-)
What does it means "it does not work"??? Does it fails at compile time or runtime? What kind of error does it shows? As of OkHttip 2.x.x, there's been a change in the way to open HttpUrlConnections, you need to include a new module and this should work:
// OkHttp 1.x:
HttpURLConnection connection = client.open(url);
// OkHttp 2.x:
HttpURLConnection connection = new OkUrlFactory(client).open(url);
see OkHttp Release notes for more information .

Categories

Resources