如何在 Retrofit 中避免 URL 编码?
How to avoid URL encoding in Retrofit?
我正在对我的网络层进行改造我遇到了一个奇怪的问题我有参数,它的值看起来像这样
store://0TxIGQMQbObzvU4Apia0V0&callback=
编码后变成这样
store://0TxIGQMQbObzvU4Apia0V0%26callback%3D
并且出于某种原因服务器不喜欢这种编码,我得到 "HTTP 400 Bad Request"。
如果我在没有编码的情况下点击它运行正常,所以我想知道有什么方法可以禁用 endoing。
我试过其他类似的方法
@Query(value "env" encoded = false) String env
但运气不好。
这是我的网络接口class
public interface NetworkService
{
@GET("v1/public/yql")
Observable<SeriesEntity> getOnGoingSeries(@Query("q") String query,
@Query("format") String format,
@Query("diagnostics") boolean flag,
@Query("env") String env);
class Factory {
public static NetworkService create()
{
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
clientBuilder.addInterceptor(loggingInterceptor);
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://query.yahooapis.com")
.client(clientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return retrofit.create(NetworkService.class);
}
}
}
编辑:
我还注意到问题只是“&”的编码值,因为如果我替换它的值(即 %26)它工作正常
我认为问题是您将 callback
参数作为 env
参数的一部分。尝试将 @Query("callback") boolean callback
添加到您的改造界面(并仅使用 store://0TxIGQMQbObzvU4Apia0V0
来表示 env
)
来自 Github issue 1199 的更好解决方案,我们可以使用自定义拦截器是解决此问题的一种方法。这个解决方案对我有用。
根据你的情况,我想在 url.
中用 = 替换 %26
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String string = request.url().toString();
string = string.replace("%26", "=");
Request newRequest = new Request.Builder()
.url(string)
.build();
return chain.proceed(newRequest);
}
});
请使用encoded = true
@Query(值="email",编码=真)
@HTTP(方法="DELETE",路径=ApiConstant.DELETE_CONTACT_INFO,hasBody=true)
Observable deleteContactInfo( @Query(value = "email", encoded = true) String email);
URL是:
https://api.themoviedb.org/3/discover/movie?api_key={"PUTAPIKEYHERE!!!}&with_genres=28
我得到:
https://api.themoviedb.org/3/discover/movie?api_key={"PUTAPIKEYHERE!!!}&with_genres%3D=28
fun getClient(codeForActionOrComedy:Int): MovieDbInterfaceToGetMovies {
val requestToApiInterceptor=Interceptor { chain ->
val url =chain.request()
.url()
.newBuilder()
// ALONE_API is just the "PUTAPIKEYHERE!!!"
.addQueryParameter("api_key","PUTAPIKEYHERE!!!")
//codeForActionOrComedy is an Int
.addQueryParameter("with_genres","$codeForActionOrComedy")
.build()
val request =chain.request()
.newBuilder()
.url(url.toString().replace("%3D","="))
.build()
return@Interceptor chain.proceed(request)
}
val okHttpClient= OkHttpClient.Builder()
.addInterceptor(requestToApiInterceptor)
.connectTimeout(60, TimeUnit.SECONDS)
.build()
val httpUrl = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(MovieDbInterfaceToGetMovies::class.java)
return httpUrl
}
我正在对我的网络层进行改造我遇到了一个奇怪的问题我有参数,它的值看起来像这样
store://0TxIGQMQbObzvU4Apia0V0&callback=
编码后变成这样
store://0TxIGQMQbObzvU4Apia0V0%26callback%3D
并且出于某种原因服务器不喜欢这种编码,我得到 "HTTP 400 Bad Request"。
如果我在没有编码的情况下点击它运行正常,所以我想知道有什么方法可以禁用 endoing。
我试过其他类似的方法
@Query(value "env" encoded = false) String env
但运气不好。
这是我的网络接口class
public interface NetworkService
{
@GET("v1/public/yql")
Observable<SeriesEntity> getOnGoingSeries(@Query("q") String query,
@Query("format") String format,
@Query("diagnostics") boolean flag,
@Query("env") String env);
class Factory {
public static NetworkService create()
{
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
clientBuilder.addInterceptor(loggingInterceptor);
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://query.yahooapis.com")
.client(clientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return retrofit.create(NetworkService.class);
}
}
}
编辑:
我还注意到问题只是“&”的编码值,因为如果我替换它的值(即 %26)它工作正常
我认为问题是您将 callback
参数作为 env
参数的一部分。尝试将 @Query("callback") boolean callback
添加到您的改造界面(并仅使用 store://0TxIGQMQbObzvU4Apia0V0
来表示 env
)
来自 Github issue 1199 的更好解决方案,我们可以使用自定义拦截器是解决此问题的一种方法。这个解决方案对我有用。
根据你的情况,我想在 url.
中用 = 替换 %26OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String string = request.url().toString();
string = string.replace("%26", "=");
Request newRequest = new Request.Builder()
.url(string)
.build();
return chain.proceed(newRequest);
}
});
请使用encoded = true
@Query(值="email",编码=真)
@HTTP(方法="DELETE",路径=ApiConstant.DELETE_CONTACT_INFO,hasBody=true)
Observable deleteContactInfo( @Query(value = "email", encoded = true) String email);
URL是:
https://api.themoviedb.org/3/discover/movie?api_key={"PUTAPIKEYHERE!!!}&with_genres=28
我得到:
https://api.themoviedb.org/3/discover/movie?api_key={"PUTAPIKEYHERE!!!}&with_genres%3D=28
fun getClient(codeForActionOrComedy:Int): MovieDbInterfaceToGetMovies {
val requestToApiInterceptor=Interceptor { chain ->
val url =chain.request()
.url()
.newBuilder()
// ALONE_API is just the "PUTAPIKEYHERE!!!"
.addQueryParameter("api_key","PUTAPIKEYHERE!!!")
//codeForActionOrComedy is an Int
.addQueryParameter("with_genres","$codeForActionOrComedy")
.build()
val request =chain.request()
.newBuilder()
.url(url.toString().replace("%3D","="))
.build()
return@Interceptor chain.proceed(request)
}
val okHttpClient= OkHttpClient.Builder()
.addInterceptor(requestToApiInterceptor)
.connectTimeout(60, TimeUnit.SECONDS)
.build()
val httpUrl = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(MovieDbInterfaceToGetMovies::class.java)
return httpUrl
}