I have found this example below to send HTTP POST message with OKHttp.
I do not understand how to pass a body string to RequestBody. Why it takes two argument?
RequestBody formBody = new FormBody.Builder()
.add("message", "Your message")
.build();
Request request = new Request.Builder()
.url("http://rhcloud.com")
.post(formBody).addHeader("operation", "modifyRecords")
.build();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(responseBody.string());
}
}
});
}
}
I'm not sure if I understand what you mean quite right, but if you are asking why the FormBody .add() takes two arguments, it's because these are Key-Value-Pairs. The first parameter is the name and the second the value.
Anyway I think this example shows a clearer way how to post a string:
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
String postBody = ""
+ "Releases\n"
+ "--------\n"
+ "\n"
+ " * _1.0_ May 6, 2013\n"
+ " * _1.1_ June 15, 2013\n"
+ " * _1.2_ August 11, 2013\n";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
Related
I'm running multiple network requests(getResponse method) in a for loop and I'm trying to get list of the responses only when ALL of the network requests are done.
I am trying to use CompletableFuture. getResponse uses OKHttp (asynch request and response)
Log.d("api_log", "Started doing things");
List<CompletableFuture> futures = new ArrayList();
for (int i = 0; i < mylist.size(); i++) {
try {
int finalI = i;
futures.add(CompletableFuture.runAsync(() -> getResponse(context, mylist.get(finalI).id)));
}
catch (Exception e) {}
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenRunAsync(() -> Log.d("api_log", "Ended doing things"));
This is the getResponse method:
private void getResponse(final Context context, final String id) {
Log.d("api_log", "id is: " + id);
final String url = context.getString(R.string.myurl) + "/" + id;
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
Request request = new Request.Builder()
.url(url)
.method("GET", null)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
return;
}
// response HAS RECEIVED
final String strResponse = response.body().string();
Log.d("api_log", "response: " + strResponse);
}
});
}
Actual: "Ended doing things" is printed before all the responses are printed.
Expected: "Ended doing things" should be printed after all the responses are printed.
How can I achieve it?
I have the following code working perfectly in Python:
login_data = {'identifier': 'something#email.com', 'password': 'Password'}
url = "https://www.duolingo.com/2017-06-30/login?fields="
p = requests.post(url, data = json.dumps(login_data))
if p.status_code is 200:
print("SUCCESS")
else:
print("ERROR")
I want to convert it to Java using OkHttp to be able to implement it in Android Studio.
I have written the following code but it gives Status Code: 422 which according to Google means Unprocessable Entity:
OkHttpClient client = new OkHttpClient();
String url = "https://www.duolingo.com/2017-06-30/login?fields=";
String login_data = "{\"identifier\": \"something#email.com\", \"password\": \"Password\"";
RequestBody body = RequestBody.create(login_data, MediaType.parse("application/json"));
Request postRequest = new Request.Builder()
.url(url)
.post(body)
.build();
client.newCall(postRequest).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", "SUCCESS - " + response.body().string());
}
else
{
Log.i("LOG", "FAILED. Status Code: " + String.valueOf(response.code));
}
}
});
All help is appreciated!
You have a missing closing bracket in the request body at java implementation.
"{\"identifier\": \"something#email.com\", \"password\": \"Password\"}"
I try to get authorization token from Twitter (app-only), the code almost fully follows oficial guide, but get 503 Service unavailable code.
#Override
protected Boolean doInBackground(Void... params) {
String cred_enc = tw_cons_key + ":" + tw_priv_cons_key;
cred_enc = Base64.encodeToString(cred_enc.getBytes(), Base64.NO_WRAP);
Request request = new Request.Builder().url("https://api.twitter.com/oauth2/token")
.header("Authorization:", "Basic " + cred_enc)
.header("Content-Type:", "application/x-www-form-urlencoded;charset=UTF-8")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
ResponseBody body = response.body();
if (response.isSuccessful()) {
Headers headers = response.headers();
//response check
for (int i = 0; i < headers.size(); i++) {
System.out.println("Headers: " + i + " " + headers.name(i) + " : " + headers.value(i));
}
System.out.println(body.string());
try {
JSONObject jsonObject = new JSONObject(body.string());
} catch (JSONException e) {
e.printStackTrace();
}
} else {
throw new IOException("Unexpected code" + response);
}
body.close();
}
});
return true;
}
What may be the possible reason?
It required me to write a simple server on localhost to find out what HTTP request was actually generated.
The problem was with colons: .header("Authorization:"resulted in Authorization:: in the network request!
After I removed colons from the header key values, both HttpUrlConnection and OkHttp code variants worked seamlessly.
I am trying to upload files in Amazon S3 using OkHttp3 library. I am able to upload the files using AsyncTask.Right now, I am showing a normal ProgressDialog. But, I want to replace the ProgressDialog with a ProgressBar. For this, I am doing the following things, but somehow it does not work:
1) Creating a custom ResponseBody and ProgressListener:
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
#Override
public MediaType contentType() {
return responseBody.contentType();
}
#Override
public long contentLength() {
return responseBody.contentLength();
}
#Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
#Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done);
}
2) Implementing the ProgressListener interface within the AsyncTask using for uploading the files:
final ProgressListener progressListener = new ProgressListener() {
#Override
public void update(long bytesRead, long contentLength, boolean done) {
Log.d(AppGlobal.TAG, " " + bytesRead);
Log.d(AppGlobal.TAG, " " + contentLength);
Log.d(AppGlobal.TAG, " " + done);
Log.d(AppGlobal.TAG, (100 * bytesRead) / contentLength + " % done ");
Log.d(AppGlobal.TAG, " " + "-------------------------");
}
};
3) Creating a OkHttp client and passing the progressListener created in Step 2 using a network interceptor:
Request request = new Request.Builder()
.header("Proxy-Authorization", "Basic " + Base64.encodeToString(data, Base64.NO_WRAP))
.addHeader("Content-Type", "application/octet-stream")
.addHeader("Connection", "Keep-Alive")
.url(url)
.put(RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(1000, TimeUnit.SECONDS)
.writeTimeout(1000, TimeUnit.SECONDS)
.readTimeout(3000, TimeUnit.SECONDS)
.proxy(proxy)
.proxyAuthenticator(proxyAuthenticator)
.addNetworkInterceptor(new Interceptor() {
#Override public okhttp3.Response intercept(Chain chain) throws IOException {
okhttp3.Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.build();
okhttp3.Response response = client.newCall(request).execute();
But, the Log.d() statements used in the "update()" function of progressListener never gets executed.
If I can get these Log statements to print, then I can update the progress bar accordingly. Can someone kindly help me out.
Here is the full code used in "doInBackground" method of AsyncTask:
#Override
protected Void doInBackground(File... inputs) {
try {
file = inputs[0];
Date expiration = new Date();
long milliSeconds = expiration.getTime();
milliSeconds += 1000 * 60 * 60; // Add 1 hour.
expiration.setTime(milliSeconds);
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(Constants.BUCKET_NAME, AppGlobal.deviceId + "/" + file.getName());
generatePresignedUrlRequest.setMethod(HttpMethod.PUT);
generatePresignedUrlRequest.setContentType("application/octet-stream");
generatePresignedUrlRequest.setExpiration(expiration);
final URL url = Util.getS3Client(UploadActivity.this).generatePresignedUrl(generatePresignedUrlRequest);
Log.d("DXXXXXX", " URL -> " + url);
String domain = AppGlobal.getDomain(UploadActivity.this);
int port = Integer.valueOf(AppGlobal.getPort(UploadActivity.this));
final String signature = AppGlobal.getSignature(UploadActivity.this);
Proxy proxy = new Proxy(Proxy.Type.HTTP,
InetSocketAddress.createUnresolved(domain, port));//the proxy server(Can be your laptop ip or company proxy)
try {
String headerVal = String.format("%s:%s", "vzServices", signature);
final byte[] data = headerVal.getBytes("UTF-8");
okhttp3.Authenticator proxyAuthenticator = new okhttp3.Authenticator() {
#Override
public Request authenticate(Route route, okhttp3.Response response) throws IOException {
String credential = Credentials.basic("vzServices", signature);
return response.request().newBuilder().header("Proxy-Authorization", credential).build();
}
};
final ProgressListener progressListener = new ProgressListener() {
#Override
public void update(long bytesRead, long contentLength, boolean done) {
Log.d(AppGlobal.TAG, " " + bytesRead);
Log.d(AppGlobal.TAG, " " + contentLength);
Log.d(AppGlobal.TAG, " " + done);
Log.d(AppGlobal.TAG, (100 * bytesRead) / contentLength + " % done ");
Log.d(AppGlobal.TAG, " " + "-------------------------");
}
};
Request request = new Request.Builder()
.header("Proxy-Authorization", "Basic " + Base64.encodeToString(data, Base64.NO_WRAP))
.addHeader("Content-Type", "application/octet-stream")
.addHeader("Connection", "Keep-Alive")
.url(url)
.put(RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(1000, TimeUnit.SECONDS)
.writeTimeout(1000, TimeUnit.SECONDS)
.readTimeout(3000, TimeUnit.SECONDS)
.proxy(proxy)
.proxyAuthenticator(proxyAuthenticator)
.addNetworkInterceptor(new Interceptor() {
#Override public okhttp3.Response intercept(Chain chain) throws IOException {
okhttp3.Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.build();
okhttp3.Response response = client.newCall(request).execute();
responseCode = response.code();
Log.d("Response code : ", " " + response.code());
Log.d("DXXXXXX", " URL 1 -> " + url);
success = true;
buffer = null;
} catch (Exception ex) {
// Handle the error
Log.d(TAG, "Error: " + ex.getLocalizedMessage());
ex.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
You should enable the progress bar first, just before calling the okhttp3 processing. Then, on response and on error, you should dismiss it.
Here's the snippet (I don't know okhttp but I've used volley many times. This example was kept simple enough to let you understand what I mean.)
sendJsonRequest(){
//enable progress bar here
enableProgressBar();
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, URL, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// dismiss it
hideProgressDialog();
System.out.println(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// dismiss it and/or handle errors
hideProgressDialog();
// ...
}
});
queue.add(jsObjRequest);
}
So I need to figure out how to access the value I get from my first response in my second. I would think that I could just store it to a a variable and access it in another request. However, that does not seem to be the case.
Here is the bit that is giving me issues. So my first request is getting me a token and then I need to use that which is stored in commatoken in my second request.
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url(API_URL + authPreferences.getToken())
.build();
client.newCall(request).enqueue(new Callback() {
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
String commatoken = response.body().string();
}
});
Request dataRequest = new Request.Builder()
.header("Authorization", "jwt"+commatoken)
.url(ChffrMe_URL).build();
client.newCall(dataRequest).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
});
}
I think we can call response.body().string() only once .... so save that data to a string variable first .. and access it wherever you need it.
String response_data;
..............
response_data = response.body().string();
You are calling response.body().string() twice ...
More info
https://stackoverflow.com/a/27922818/3552066
If you want to avoid about empty result:
assert response.body() != null;
String r = response.body().string();
And if you want access to each elements :
JSONObject json = new JSONObject(r);
Log.i("love", "Res: "+json.getString("result")); //Name -> Answer
See the result:
{"fname":"John","sname":"Alice","percentage":"46","result":"Can choose someone better."} // String from
I/love: Res: All the best! // Json form by Name