I have a retrofit request
#GET("{link}")
suspend fun getFilePart(#Path(value = "link") link: String): Deferred<NetworkResponse<ResponseBody, NetworkError>>
and when i call it i pass a 'link'
val base = if (BuildConfig.DEBUG) BuildConfig.TRANSFER_URL_DEBUG else BuildConfig.TRANSFER_URL
apiManager.appApiService(base).getFilePart(it.link)
Lets say the link is something like "https://storage_dev.example.com/10002/6d197e1e57e37070760c4ae28bf1..." but in the Logcat i see that some characters get urlEncoded.
For example
the following Url
https://storage_dev.example.com/10002/6d197e1e57e37070760c4ae28bf18d813abd35a372b6a1f462e4cef21e505860.1&Somethingelse
turns to
https://storage_dev.example.com/10002/6d197e1e57e37070760c4ae28bf18d813abd35a372b6a1f462e4cef21e505860.1%3FSomethingelse
As i can see the link is a String that has many characters inside that get encoded like "&" has turned to "%3F"
How can i prevent this?
You can add encoded = true to your request param to tell retrofit to not encode it again:
/**
* Specifies whether the parameter {#linkplain #value() name} and value are already URL encoded.
*/
boolean encoded() default false;
Example:
#Path(value = "link", encoded = true)
If your link includes the baseurl part you should use #Url to avoid that problem
#GET
suspend fun getFilePart(#Url link: String): Deferred<NetworkResponse<ResponseBody, NetworkError>>
I think I'm late but however this is how I solved it ..
my issue was the url to containes " so on request url it gets encoded then looks like this domain.com/api/%22SOME_URL_%22
simply just add interceptor to catch the request and decode it.
if(it.request().url().toString().contains("api/MY_SUB_DOMAIN")){
val newUrl = java.net.URLDecoder.decode( it.request().url().toString(),
StandardCharsets.UTF_8.name()) // <--- This is your main solution (decode)
.replace("\"", "") // <---- I had to do this to remove parenthasis "
requestBuilder.url(newUrl) // <--- DONT FORGET TO ASSAIGN THE NEW URL
}
Related
I have a strange behaviour when I click on a link in a webview that is a PDF file link.
For example: https://my.server.com/foobar.pdf
So I have made some research and this link will start a dowload in my webview.
I have a DownloadListener and a onDownloadStart method.
In it I send the URL to Android so that PDF apps on phone can open it.
My strange behaviour is here. If the link in the webview does not have parameters I am not able to add parameters in the URL but if the URL have one parameter -> my parameters are added.
Example will be more meaningful.
Here url in link is "https://my.server.com/foobar.pdf"
val uriTest = Uri.parse(url).buildUpon()
.appendQueryParameter("key1", val1)
.appendQueryParameter("key2", val2)
.build()
val intent = Intent(Intent.ACTION_VIEW, uriTest)
startActivity(intent)
So when the PDF app called by startActivity(intent) call the URL on my server I have no parameters in URL and on my server I see a call to "https://my.server.com/foobar.pdf" not to "https://my.server.com/foobar.pdf?key1=val1&key2=val2".
BUT
If the url in link is "https://my.server.com/foobar.pdf?t=t" when my Android code is executed on my server side I can see a call to ""https://my.server.com/foobar.pdf?t=t&key1=val1&key2=val2". My parameters are added in this case.
Is it normal? Am I missing something?
Thanks for your help!
---EDIT---
I also tried to add my parameters in the string directly and it is the same -> my parameters are ignored until the URL I get has one parameter.
Example: I get "https://my.server.com/foobar.pdf" and I do:
val url1 = url + "?key1=" + val1
or
val url1 = "$url?key1=$val1"
val yourUrl = StringBuilder("https://my.server.com/foobar.pdf")
val parameters = hashMapOf<String, String>()
parameters["key1"] = "val1"
parameters["key2"] = "val2"
var count = 0
for (i in parameters.entries) {
if (count == 0)
yourUrl.append("?${i.key}=${i.value}&")
else
yourUrl.append("${i.key}=${i.value}&")
count++
}
val yourNewUrl = yourUrl.substring(0, yourUrl.length - 1)
Timber.e("URL: $yourNewUrl")
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(yourNewUrl))
startActivity(intent)
Happy coding :)
i want to check the youtube url is username or channelid ?
for example https://www.youtube.com/user/aaaaaaaa
https://www.youtube.com/channel/UC--------hdch . how to check?
You can check if the url contains the string user for User and channel for Channel.
String url = "https://www.youtube.com/user/aaaaaaaa"
if(url.contains("/channel/")){
//url is a channel url
}else if(url.contains("/user/")){
//url is a user url
}
Well the problem is that you have to verify that there is a link to user or a channel directly after the youtube address,
val url: String = "https://www.youtube.com/user/aaaaaaaa"
if(url.contains("/channel/")){
//url is a channel url
}else if(url.contains("/user/")){
//url is a user url
}
Here I didn't used to check if the string contains youtube.com/user/ because some urls may have youtu.be/user/ which is valid and offical address, so just checking that there is forward slash before and after the identifier it makes sure that it'll work as expected!
EDIT1:
OP wants a regex solution so:
val regex = Regex("""(?:youtube\.com|youtu\.be)\/(user|channel)""")
val result = regex.find("https://www.youtube.com/user/aaaaaaaa")
when(result!!.groupValues[1]){
"user" -> //code
"channel" -> //code
else -> {} //or replace {} with code
}
EDIT2:
You could use this expression to get the information about the url
val regex = Regex("""(?:https:\/\/)*(?:www\.)*(youtube\.com|youtu\.be)\/(user|channel)\/(\w+)""")
val result = regex.find("https://www.youtube.com/user/aaaaaaaa")!!
when(result.groupValues[2]){
"user" -> //code
"channel" -> //code
else -> {} //or replace {} with code
}
println(result.groupValues[0]) //https://www.youtube.com/user/aaaaaaaa
println(result.groupValues[1]) //youtube.com
println(result.groupValues[2]) //user
println(result.groupValues[3]) //aaaaaaaa
EDIT3:
As OP suggested this does not work for a symbol (non word literal) hence, instead of /w+ you could use .+
So the finalized regex would be
(?:https:\/\/)*(?:www\.)*(youtube\.com|youtu\.be)\/(user|channel)\/(.+)
I am trying out Ktor by converting some existing project that's currently using Retrofit.
Although I could easily convert the request into something like:
client.get {
url("$BASE_URL/something/somepage/another")
}
It seems very tedious to always add the $BASE_URL to all paths every time. In retrofit, we could simply do something like:
Retrofit.Builder()
.baseUrl(BASE_URL)
.create(SomeServiceClass::class.java)
I've triede using defaultRequest and setting the BASE_URL there but apparently you could only set the url.host and not the whole basePath.
Is there a way to do the same thing in Ktor? or if there is none, what's the best practice to handle this?
You can!
In order to do so you need to set your default request when you instantiate your client.
val httpClient = HttpClient(Android) {
defaultRequest {
host = "my.zoo.com"
url {
protocol = URLProtocol.HTTPS
}
}
}
val response = httpClient.get<List<CatsResponse>>(
path = "animals/cats"
)
This will call https://my.zoo.com/animals/cats
Hope it helps :)
I am trying to use theDuckDuck go api with this code
val mainVal = searchQuery.replace(" ", "+")
val url = URL("https://api.duckduckgo.com/?q=$mainVal&format=json")
println(url.host)
url.openConnection()
val json = url.readText()
I am getting this error as a result
java.io.IOException: Server returned HTTP response code: 500 for URL: https://api.duckduckgo.com/?q=duck+duck+go&format=json
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1919)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1515)
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:250)
at java.base/java.net.URL.openStream(URL.java:1139)
at kotlin.io.TextStreamsKt.readBytes(ReadWrite.kt:150)
at com.andromeda.araserver.skills.GetInfo.getFast(GetInfo.kt:82)
at com.andromeda.araserver.skills.GetInfo.searchBing(GetInfo.kt:43)
at com.andromeda.araserver.skills.GetInfo.main(GetInfo.kt:28)
at com.andromeda.araserver.Run.serve(Run.java:98)
at fi.iki.elonen.NanoHTTPD$HTTPSession.execute(NanoHTTPD.java:945)
at fi.iki.elonen.NanoHTTPD$ClientHandler.run(NanoHTTPD.java:192)
at java.base/java.lang.Thread.run(Thread.java:834)
When I run the given link in my browser it returns the expected result. I tried using the HttpSConnection method, it did not work.
note I have used this methood literly hundreds of times on https, thats not the issue.
Make sure you added INTERNET permission in Manifest
&
Instead adding "+" use Uri.encode method for encoding URLs :
// val mainVal = searchQuery.replace(" ", "+")
val mainVal = Uri.encode(searchQuery)
val url = URL("https://api.duckduckgo.com/?q=$mainVal&format=json")
println(url.host)
url.openConnection()
val json = url.readText()
println("Result = " + json)
This is the API I want to get: http://itunes.apple.com/us/rss/topsongs/limit=20/genre=29/explicit=true/json
How can I replace "29" by another number programmatically?
I have read many docs, but all of them have the same form with "?". Ex: https://api.example.com/tasks?id=123. I cannot apply their solution to my problem.
Thanks for your help.
Try this
#GET("users/{user}/repos")
Call<Response> listRepos(#Path("user") String user)
Try with
int your_number = 20;
String url = "http://itunes.apple.com/us/rss/topsongs/limit=20/genre=29/explicit=true/json;"
url = url.replace("genre=29", "genre"+your_number);
and now use url for requesting.