I am trying to call a post API with Retrofit using coroutine but after hours of searching I am unable to find the mistake. There is no clear information about the error.
Below is the simple JSON I should be getting after posting the data.
{
"status": "OK",
"data": 5,
"message": null,
"code": "200"
}
api call from fragment
lifecycleScope.launchWhenStarted {
sharedPreferences.getString(AppConstant.token, "")?.let { authToken ->
viewModelSubProperty.sendDetail(authToken,propertyData)
}
}
where propertyData is the values I am send to the api.
ViewModel
suspend fun sendDetail(token: String,data: SubPropertyData) {
viewModelScope.launch(Dispatchers.IO) {
val responseResult = repository.sendDetail(token = token,data)
withContext(Dispatchers.Main) {
if(responseResult is Result.Success) {
Log.e("Viewmodel", "${responseResult.data}")
Log.e("Viewmodel", "$responseResult")
}
else if (responseResult is Result.Error && responseResult.exception.message == AppConstant.INTERNET_ERR_MSG)
EventBus.getDefault().post(WebServiceErrorEvent(null, true))
else if (responseResult is Result.Error)
EventBus.getDefault().post(WebServiceErrorEvent(responseResult))
}
}
}
DataSource
suspend fun sendDetail(token: String, data: SubPropertyData): Result<AddUpdateDataResponse> {
val serverResponse: Response<AddUpdateDataResponse>
return try {
serverResponse = serverApi.sendDetail(token,data)
if(serverResponse.isSuccessful)
Result.Success(serverResponse.body()!!)
else {
Log.e("what-code ", ""+serverResponse.errorBody())
Log.e("what-code ", serverResponse.errorBody()?.charStream().toString())
Result.Success(serverResponse.body()!!)
}
} catch (e: Throwable) {
if(e is NoConnectivityException)
Result.Error(IOException(AppConstant.INTERNET_ERR_MSG))
else
Result.Error(IOException(e.localizedMessage))
}
}
Api Call
#POST("api/addOrUpdateSubjectPropertyDetail")
suspend fun sendDetail(
#Header("Authorization") Authorization:String,
#Body data: SubPropertyData
) : Response<AddUpdateDataResponse>
Pojo class
data class AddUpdateDataResponse(
#SerializedName("code")
val code: String?,
#SerializedName("data")
val data: Int?,
#SerializedName("message")
val message: String? = null,
#SerializedName("status")
val status: String?
)
Logs
I/okhttp.OkHttpClient: --> POST https://abc/api/AddOrUpdateSubjectPropertyDetail
Content-Type: application/json; charset=UTF-8
Content-Length: 398
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiI0IiwiaHR0cDovL3NjaGVtYXnzK5gv0k4
I/okhttp.OkHttpClient: {"address":{"city":"Karachi","countryId":1,"countryName":"Pak","countyId":1,"countyName ":"SSS","stateId":11,"stateName":"Sindh","street":"akl","unit":"00","zipCode":"123"},"appraisedPropertyValue":100000.0,"floodInsurance":0.0,"homeOwnerInsurance":200.0,"isMixedUseProperty":true,"loanApplicationId":5,"mixedUsePropertyExplanation":"ashh","occupancyTypeId":1,"propertyTax":100.0,"propertyTypeId":1}
--> END POST (398-byte body)
--> END POST (398-byte body)
I/okhttp.OkHttpClient: <-- 500
https://abc/api/AddOrUpdateSubjectPropertyDetail (167ms)
I/okhttp.OkHttpClient: server: Microsoft-IIS/10.0
I/okhttp.OkHttpClient: x-powered-by: ASP.NET
date: Mon, 08 Nov 2021 22:31:31 GMT
I/okhttp.OkHttpClient: <-- END HTTP (0-byte body)
E/what-code: null
null
okhttp3.ResponseBody$BomAwareReader#3554188
Related
So I'm still in the process of learning android dev and I'm currently working on an app which is supposed to show students their grades. Right now I am stuck at getting login to a service from which grades are collected. For that process I am using https://eduo-ocjene-docs.vercel.app/ api (documentation is in Croatian).
This is what curl request for logging in looks like:
curl --location --request GET 'https://ocjene.eduo.help/api/login' \--header 'Content-Type: application/json' \--data-raw '{ "username":"ivan.horvat#skole.hr", "password":"ivanovPassword123"}'
Here are screenshots of what I have tried until now
Here is how I build retrofit
object ApiModule {
private const val BASE_URL = "https://ocjene.eduo.help/"
lateinit var retrofit: EdnevnikApiService
private val json = Json { ignoreUnknownKeys = true }
fun initRetrofit() {
val okhttp = OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}).build()
retrofit = Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.client(okhttp).build().create(EdnevnikApiService::class.java)
}
}
The login method
interface EdnevnikApiService {
#HTTP(method = "get", path = "/api/login", hasBody = true)
fun login(#Body request: LoginRequest): Call<LoginResponse>
}
This is what happens when the login button is clicked
fun onLoginButtonClicked(email: String, password: String) {
val request = LoginRequest(email, password)
ApiModule.retrofit.login(request).enqueue(object : Callback<LoginResponse> {
override fun onResponse(call: Call<LoginResponse>, response: Response<LoginResponse>) {
loginResultLiveData.value = response.isSuccessful
val body = response.body()
}
override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
loginResultLiveData.value = false
}
})
}
and this is what kotlin request and kotlin response data classes look like
#kotlinx.serialization.Serializable
data class LoginRequest(
#SerialName("username") val username: String,
#SerialName("password") val password: String,
)
#kotlinx.serialization.Serializable
data class LoginResponse(
#SerialName("LoginSuccessful") val isSuccessful: Boolean,
)
Oh and this is what I get from the interceptor when I send the request
My guess is server is responding with 400 Bad Request due to unsupported method type. When I replaced method = "get" with method = "GET" in your sample code, I received:
java.lang.IllegalArgumentException: method GET must not have a request body.
which makes sense. Luckily, the /login API you shared works with POST method type, so you can try using:
#HTTP(method = "POST", path = "/api/login", hasBody = true,)
I checked at my end and I received the following response:
<-- 200 https://ocjene.eduo.help/api/login (1390ms)
access-control-allow-origin: *
access-control-allow-credentials: true
set-cookie: epicCookie=f69fbd6d4f10b5cc38e038b5da0843b356776c58c4fb32aed24dbcc49026778724bc25e21448c05a29df9f4b5558b254011fb3f8a992710f9901f23c53be5eaadaa799f3f5ac9e18de191bed02ef3e96030b83042ee8392755b03dd785edca6a;
content-type: application/json; charset=utf-8
etag: "bkrbkvg0eo6c"
vary: Accept-Encoding
date: Thu, 10 Nov 2022 03:07:08 GMT
server: Fly/b1863e2e7 (2022-11-09)
via: 2 fly.io
fly-request-id: 01GHFR2T56X9K0GFN3DH1Z9JYV-sin
{"LoginSuccessful":false,"token":"f69fbd6d4f10b5cc38e038b5da0843b356776c58c4fb32aed24dbcc49026778724bc25e21448c05a29df9f4b5558b254011fb3f8a992710f9901f23c53be5eaadaa799f3f5ac9e18de191bed02ef3e96030b83042ee8392755b03dd785edca6a"}
<-- END HTTP (228-byte body)
object ApiModule {
private const val BASE_URL = "https://ocjene.eduo.help/"
lateinit var retrofit: EdnevnikApiService
private val json = Json { ignoreUnknownKeys = true }
fun initRetrofit() {
val okhttp = OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}).build()
retrofit = Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.client(okhttp).build().create(EdnevnikApiService::class.java)
}
}
I want to get altitude from api service and:
base url is https://api.open-elevation.com/
end point is api/v1/lookup?
and get two args lat and long like this
https://api.open-elevation.com/api/v1/lookup?locations=42,35
output is a json
How can i send get request and get data and please help
Hm. unfortunately you can't send a request with varargs through retrofit. But, you can do it like this.
Do something like this..
lifecycleScope.launch {
val latLong = arrayOf(41.161758, -8.583933)
val result = withContext(Dispatchers.IO) {
RetroClient.getInstance().lookup(latLong.joinToString())
}.awaitResponse()
if (result.isSuccessful && result.code() == 200) {
// If success do your sutff here
}
}
RetroClient
object RetroClient {
private val httpInterceptor by lazy {
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
}
private val client by lazy {
OkHttpClient.Builder()
.addInterceptor(httpInterceptor)
.callTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS)
.build()
}
private val gson by lazy {
GsonBuilder().setLenient().create()
}
fun getInstance(): RetroInterface {
return Retrofit.Builder()
.baseUrl("https://api.open-elevation.com/api/v1/")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson)).build()
.create(RetroInterface::class.java)
}
}
RetroInterface
interface RetroInterface {
#GET("lookup")
fun lookup(
#Query("locations") locations: String,
): Call<LocationsModel?>
}
LocationsModel
data class LocationsModel(
var results: List<Result>?
)
data class Result(
var elevation: Int?,
var latitude: Double?,
var longitude: Double?
)
RESULTS
I/okhttp.OkHttpClient: <-- 200 OK https://api.open-elevation.com/api/v1/lookup?locations=41.161758%2C%20-8.583933 (1411ms)
I/okhttp.OkHttpClient: Server: nginx/1.21.1
I/okhttp.OkHttpClient: Date: Sat, 27 Aug 2022 18:33:55 GMT
I/okhttp.OkHttpClient: Content-Type: application/json
I/okhttp.OkHttpClient: Transfer-Encoding: chunked
I/okhttp.OkHttpClient: Connection: keep-alive
I/okhttp.OkHttpClient: Access-Control-Allow-Origin: *
I/okhttp.OkHttpClient: Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
I/okhttp.OkHttpClient: Access-Control-Allow-Headers: Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token
I/okhttp.OkHttpClient: Strict-Transport-Security: max-age=31536000; includeSubDomains
I/okhttp.OkHttpClient: {"results": [{"latitude": 41.161758, "longitude": -8.583933, "elevation": 117}]}
I/okhttp.OkHttpClient: <-- END HTTP (80-byte body)
Hope you understand. - Thank you.
Uploading to S3 signed URL's with a file as an origin works without problems, but trying to do it with an Uri I get from my ActivityResult is not working for me.
Here is what I try:
I'm using a InputStreamRequestBody class like described here: https://commonsware.com/blog/2020/07/05/multipart-upload-okttp-uri.html
class InputStreamRequestBody(
private val contentType: MediaType,
private val contentResolver: ContentResolver,
private val uri: Uri
) : RequestBody() {
override fun contentType() = contentType
override fun contentLength(): Long = -1
#Throws(IOException::class)
override fun writeTo(sink: BufferedSink) {
val input = contentResolver.openInputStream(uri)
input?.use { sink.writeAll(it.source()) }
?: throw IOException("Could not open $uri")
}
}
My Retrofit UploadAPI interface:
interface UploadAPI {
#PUT
suspend fun uploadFile(
#Header("x-amz-acl") contentType: String,
#Url uploadUrl: String,
#Body file: RequestBody
): Response<Unit>
companion object {
const val BASE_URL = "https://....com"
}
}
And here my Retrofit Singleton in AppModule:
#Provides
#Singleton
fun provideUploadApi(): UploadAPI {
return Retrofit.Builder()
.baseUrl(UploadAPI.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(UploadAPI::class.java)
}
And then calling the InputStreamRequestBody class with my Uri (in my repository) and calling the retrofit instance and upload function:
val resolver = context.contentResolver
val type = ("image/jpeg").toMediaType()
val contentPart = InputStreamRequestBody(type, resolver, content)
uploadAPI.uploadFile(
"public-read",
mySignedUrl,
contentPart
)
this is what my logginInterceptor tells me:
2022-05-19 22:16:48.844 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: --> PUT https://app-content.ams3.digitaloceanspaces.com/Files/Test/profilbild.webp?Content-Type=image%2Fwebp&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=CENSORED-Amz-SignedHeaders=host%3Bx-amz-acl&x-amz-acl=public-read
2022-05-19 22:16:48.844 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: Content-Type: image/jpeg
2022-05-19 22:16:48.844 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: x-amz-acl: public-read
2022-05-19 22:16:48.896 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: --> END PUT (binary -1-byte body omitted)
2022-05-19 22:16:49.503 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: <-- 411 Length Required https://app-content.ams3.digitaloceanspaces.com/Files/Test/profilbild.webp?Content-Type=image%2Fwebp&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=CENSORED-Amz-SignedHeaders=host%3Bx-amz-acl&x-amz-acl=public-read (606ms)
2022-05-19 22:16:49.504 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: content-length: 239
2022-05-19 22:16:49.504 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: x-amz-request-id: tx000000000000004541b27-00622f61-20f93ecc-ams3c
2022-05-19 22:16:49.505 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: accept-ranges: bytes
2022-05-19 22:16:49.505 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: content-type: application/xml
2022-05-19 22:16:49.505 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: date: Thu, 19 May 2022 15:16:49 GMT
2022-05-19 22:16:49.505 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: cache-control: max-age=60
2022-05-19 22:16:49.506 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: strict-transport-security: max-age=15552000; includeSubDomains; preload
2022-05-19 22:16:49.506 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: connection: close
2022-05-19 22:16:49.506 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: <?xml version="1.0" encoding="UTF-8"?><Error><Code>MissingContentLength</Code><BucketName>app-content</BucketName><RequestId>tx00000000000000fffb27-0062865f61-20f93ecc-ams3c</RequestId><HostId>20f93ecc-ams3c-ams3-zg03</HostId></Error>
2022-05-19 22:16:49.507 8469-8703/com.havanasun.loginplayground I/okhttp.OkHttpClient: <-- END HTTP (239-byte body)
I have the strong feeling that I cannot just pass the instance of InputStreamRequestBody as a requestBody eventhough this class inherrits from RequestBody.
This is the response.body I'm receiving
D/OkHttp: <-- 201 Created http://192.168.0.2:8000/api/surveys (962ms)
D/OkHttp: Host: 192.168.0.2:8000
D/OkHttp: Date: Thu, 23 Apr 2020 15:25:40 GMT
D/OkHttp: Connection: close
D/OkHttp: X-Powered-By: PHP/7.3.10
D/OkHttp: Cache-Control: no-cache, private
D/OkHttp: Date: Thu, 23 Apr 2020 15:25:40 GMT
D/OkHttp: Content-Type: application/json
D/OkHttp: X-RateLimit-Limit: 60
D/OkHttp: X-RateLimit-Remaining: 59
//this is what I want to save
D/OkHttp: [{"id":2,"evaluation_id":1,"user_id":null,"group_id":1,"created_at":"2020-04-20 11:04:31",
"updated_at":"2020-04-20 11:04:31","answered":false,"evaluation":{"id":1,"survey_id":1,
"init_date":"2020-04-13 12:00:00","end_date":"2020-04-30 12:00:00","report":0,"report_date":null,
"report_end":null,"created_at":"2020-04-20 11:04:21","updated_at":"2020-04-20 11:04:21",
"survey":{"id":1,"name":"asdfasdfds group","description":"<p>adfadsfa<strong><em>dsf<\/em>
<\/strong>asdfadsf asd asdf f sad fsd<\/p>","user_id":1,"anonymous":0,"created_at":"2020-04-20 11:04:21",
"updated_at":"2020-04-20 11:04:31"}}},{"id":5,"evaluation_id":2,"user_id":1,"group_id":null,
"created_at":"2020-04-21 11:00:19","updated_at":"2020-04-21 11:00:19","answered":true,
"evaluation":{"id":2,"survey_id":2,"init_date":"2020-04-13 12:00:00","end_date":"2020-04-24 12:00:00","report":0,
"report_date":null,"report_end":null,"created_at":"2020-04-20 11:05:43","updated_at":"2020-04-20 11:05:43",
"survey":{"id":2,"name":"asdfa single","description":"<p>asdfa<\/p>","user_id":1,"anonymous":1,
"created_at":"2020-04-20 11:05:43","updated_at":"2020-04-21 11:00:19"}}}]
D/OkHttp: <-- END HTTP (1123-byte body)
I have created the POJO models for the objects inside the main object, this is a retrofit response so I have it like this for now
#Override
public void onResponse(Call<Survey> call, Response<Survey> response) {
if (!response.isSuccessful()) {
FancyToast.makeText(activity, getString(R.string.error),
FancyToast.LENGTH_SHORT, FancyToast.CONFUSING,
R.drawable.error_outline, false).show();
return;
}
System.out.println("response: " + response.body());
}
How do I get the JSON from the response body to then save in the models?
Here is how your model class should be:
class Model : ArrayList<ModelItem>(){
data class ModelItem(
val answered: Boolean = false,
val created_at: String = "",
val evaluation: Evaluation = Evaluation(),
val evaluation_id: Int = 0,
val group_id: Int = 0,
val id: Int = 0,
val updated_at: String = "",
val user_id: Int = 0
) {
data class Evaluation(
val created_at: String = "",
val end_date: String = "",
val id: Int = 0,
val init_date: String = "",
val report: Int = 0,
val report_date: Any = Any(),
val report_end: Any = Any(),
val survey: Survey = Survey(),
val survey_id: Int = 0,
val updated_at: String = ""
) {
data class Survey(
val anonymous: Int = 0,
val created_at: String = "",
val description: String = "",
val id: Int = 0,
val name: String = "",
val updated_at: String = "",
val user_id: Int = 0
)
}
}
}
Make sure your are using GSON converter library in your retrofit.
I'm trying to parse the JSON from this URL, https://fantasy.premierleague.com/drf/elements but the response I get from okhttp and Postman are different. I've also used online API testers and I get a response back with the full JSON there as well. I'm not sure why my code isn't working.
Can anyone help me figure this out?
Here's the code I'm using for quick testing.
val request = Request.Builder()
.url("https://fantasy.premierleague.com/drf/elements")
.get()
.addHeader("accept", "*/*")
.addHeader("accept-encoding", "gzip, deflate")
.addHeader("cache-control", "no-cache")
.addHeader("connection", "keep-alive")
.cacheControl(CacheControl.FORCE_NETWORK)
.build()
val httpClient = OkHttpClient()
httpClient.newCall(request).enqueue(object : okhttp3.Callback {
override fun onFailure(call: okhttp3.Call?, e: IOException?) {
Timber.d("FPL response failed = " + e?.message.toString())
}
override fun onResponse(call: okhttp3.Call?, response: okhttp3.Response?) {
if (response!!.isSuccessful) {
val responseBody = response.body()?.string()
try {
val obj = JSONObject(responseBody)
Timber.d("FPL response = " + obj.toString())
} catch (t: Throwable) {
Timber.e("Could not parse malformed JSON: " + t.message)
}
Timber.d("FPL response = $response")
Timber.d("FPL headers = " + response.headers())
Timber.d("FPL body = " + responseBody)
} else {
Timber.d("FPL response failed = " + response.body().toString())
}
}
})
I tried replicating Postman's code snippet headers which are:
Request request = new Request.Builder()
.url("https://fantasy.premierleague.com/drf/elements")
.get()
.addHeader("cache-control", "no-cache")
.addHeader("postman-token", "05ae03ef-cf44-618c-a82c-5762e245b771")
.build();
but sadly no luck there either.
Log:
D/HomeController$onAttach:L135: FPL response = Response{protocol=http/1.1, code=200, message=OK, url=https://fantasy.premierleague.com/drf/elements}
D/HomeController$onAttach:L138: FPL headers =
Server: Varnish
Retry-After: 0
Content-Type: application/json
Content-Length: 0
Accept-Ranges: bytes
Date: Tue, 15 Aug 2017 22:17:18 GMT
Via: 1.1 varnish
Connection: close
X-Served-By: cache-jfk8123-JFK
X-Cache: MISS
X-Cache-Hits: 0
X-Timer: S1502835438.419014,VS0,VE0
D/HomeController$onAttach:L139: FPL body =
As you can see, the body is empty and "Connection" is close.
Here's the response headers that Postman gets, much different.
Accept-Ranges →bytes
Age →14
Allow →GET, HEAD, OPTIONS
Cache-Control →no-cache, no-store, must-revalidate, max-age=0
Connection →keep-alive
Content-Encoding →gzip
Content-Language →plfplen
Content-Length →39518
Content-Type →application/json
Date →Tue, 15 Aug 2017 00:54:32 GMT
Edge-Control →max-age=60
Fastly-Debug-Digest →fdb44d2dd7c0b26c639a8b3476f8c63661c68707cc3b9446f8ed3941cd3fe01e
Server →nginx
Vary →Accept-Encoding
Via →1.1 varnish
Via →1.1 varnish
X-Cache →HIT, MISS
X-Cache-Hits →1, 0
X-Frame-Options →DENY
X-Served-By →cache-lcy1146-LCY, cache-jfk8143-JFK
X-Timer →S1502758472.116470,VS0,VE82
as you can see, "Connection" says keep alive.
Is there something I'm missing in my Request.Builder() to get this to work?
EDIT:
So, I decided to try making the request using an AsyncTask, and got the full JSON back as you can see in the log under. I don't understand why Okhttp3 isn't working.
val url = params[0]
var stream: InputStream? = null
var connection: HttpsURLConnection? = null
var result: String? = null
try {
connection = url?.openConnection() as HttpsURLConnection?
// Timeout for reading InputStream arbitrarily set to 3000ms.
connection?.readTimeout = 3000
// Timeout for connection.connect() arbitrarily set to 3000ms.
connection?.connectTimeout = 3000
// For this use case, set HTTP method to GET.
connection?.requestMethod = "GET"
// Already true by default but setting just in case; needs to be true since this request
// is carrying an input (response) body.
connection?.doInput = true
// Open communications link (network traffic occurs here).
connection?.connect()
val responseCode = connection?.responseCode
if (responseCode != HttpsURLConnection.HTTP_OK) {
throw IOException("HTTP error code: " + responseCode)
}
// Retrieve the response body as an InputStream.
stream = connection?.inputStream
Timber.d("httpurl stream = " + connection?.inputStream.toString())
if (stream != null) {
// Converts Stream to String with max length of 500.
result = readStream(stream, 500)
}
} finally {
// Close Stream and disconnect HTTPS connection.
if (stream != null) {
stream.close()
}
if (connection != null) {
connection.disconnect()
}
}
return result
Log:
D/HomeController$NetworkA:L266: httpurl response = [{"id":1,"photo":"48844.jpg","web_name":"Ospina","team_code":3,"status":"a","code":48844,"first_name":"David","second_name":"Ospina","squad_number":13,"news":"","now_cost":50, .... }]
Your problem is User-Agent header. Here is a working example:
fun syncGetOkHttp() {
println("\n===")
println("OkHttp")
println("===")
val client = OkHttpClient().newBuilder()
.addNetworkInterceptor { chain ->
val (request, response) = chain.request().let {
Pair(it, chain.proceed(it))
}
println("--> ${RequestLine.get(request, Proxy.Type.HTTP)})")
println("Headers: (${request.headers().size()})")
request.headers().toMultimap().forEach { k, v -> println("$k : $v") }
println("<-- ${response.code()} (${request.url()})")
val body = if (response.body() != null)
GZIPInputStream(response.body()!!.byteStream()).use {
it.readBytes(50000)
} else null
println("Response: ${StatusLine.get(response)}")
println("Length: (${body?.size ?: 0})")
println("""Body: ${if (body != null && body.isNotEmpty()) String(body) else "(empty)"}""")
println("Headers: (${response.headers().size()})")
response.headers().toMultimap().forEach { k, v -> println("$k : $v") }
response
}
.build()
Request.Builder()
.url(url)
.header("Accept", "application/json")
.header("User-Agent", "Mozilla/5.0")
.build()
.let { client.newCall(it).execute() }
}