设置动态的基础 URL 使用便携式2.0和匕首2

我正在尝试使用匕首2来执行一个登录操作

以下是我如何设置“改造依赖项”

@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient client) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson)
.client(client)
.baseUrl(application.getUrl())
.build();
return retrofit;
}

这是 API 接口。

interface LoginAPI {
@GET(relative_path)
Call<Boolean> logMe();
}

我有三个不同的基本网址用户可以登录。因此,我不能设置一个静态的网址,同时设置龟裂依赖。我在 Application 类上创建了一个 setUrl ()和 getUrl ()方法。在用户登录时,我在调用 API 调用之前将 URL 设置为 Application。

我使用延迟注射进行这样的改造

Lazy<Retrofit> retrofit

那样的话,匕首只有在我能打电话的时候才会注入依赖性

retrofit.get()

这部分很好用。我把网址设置为改进依赖关系。然而,当用户输入错误的基本 url (比如 mywifi.domain.com ) ,理解错误的 url 并修改它(比如 mydata.domain.com )时,问题就出现了。因为匕首已经创建了改造的依赖,它不会再做。 所以我必须重新打开应用程序,输入正确的网址。

我阅读了不同的文章,建立动态网址的逆转使用匕首。对我来说,没有一件事是真正有效的。我错过什么了吗?

62540 次浏览

对这个用例的支持在逆转录2中被删除了。建议使用 OkHttp 拦截器代替。

HostSelectionInterceptor 制作人: 斯旺克耶西

import java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;


/** An interceptor that allows runtime changes to the URL hostname. */
public final class HostSelectionInterceptor implements Interceptor {
private volatile String host;


public void setHost(String host) {
this.host = host;
}


@Override public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String host = this.host;
if (host != null) {
//HttpUrl newUrl = request.url().newBuilder()
//    .host(host)
//    .build();
HttpUrl newUrl = HttpUrl.parse(host);
request = request.newBuilder()
.url(newUrl)
.build();
}
return chain.proceed(request);
}


public static void main(String[] args) throws Exception {
HostSelectionInterceptor interceptor = new HostSelectionInterceptor();


OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();


Request request = new Request.Builder()
.url("http://www.coca-cola.com/robots.txt")
.build();


okhttp3.Call call1 = okHttpClient.newCall(request);
okhttp3.Response response1 = call1.execute();
System.out.println("RESPONSE FROM: " + response1.request().url());
System.out.println(response1.body().string());


interceptor.setHost("www.pepsi.com");


okhttp3.Call call2 = okHttpClient.newCall(request);
okhttp3.Response response2 = call2.execute();
System.out.println("RESPONSE FROM: " + response2.request().url());
System.out.println(response2.body().string());
}
}

或者你可以替换你的卢克菲特实例(也可以把实例存储在 RetrofitHolder中,你可以在 RetrofitHolder中修改实例本身,并通过 Dagger 提供持有者) ..。

public class RetrofitHolder {
Retrofit retrofit;


//getter, setter
}

或者重用你当前的“改造”实例,用反射修改新的 URL,因为去他的规则。改造有一个 baseUrl参数,即 private final,因此您只能通过反射访问它。

Field field = Retrofit.class.getDeclaredField("baseUrl");
field.setAccessible(true);
okhttp3.HttpUrl newHttpUrl = HttpUrl.parse(newUrl);
field.set(retrofit, newHttpUrl);

卢克菲特2库带有一个 @Url注释,你可以像这样覆盖 baseUrl:

API 接口:

public interface UserService {
@GET
public Call<ResponseBody> profilePicture(@Url String url);
}

然后像这样调用 API:

Retrofit retrofit = Retrofit.Builder()
.baseUrl("https://your.api.url/");
.build();


UserService service = retrofit.create(UserService.class);
service.profilePicture("https://s3.amazon.com/profile-picture/path");

更多细节请参考这个链接: https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests

感谢@EpicPandaForce 的帮助。如果有人面临着 IllegalArgumentException,这是我的工作代码。

public class HostSelectionInterceptor implements Interceptor {
private volatile String host;


public void setHost(String host) {
this.host = HttpUrl.parse(host).host();
}


@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String reqUrl = request.url().host();


String host = this.host;
if (host != null) {
HttpUrl newUrl = request.url().newBuilder()
.host(host)
.build();
request = request.newBuilder()
.url(newUrl)
.build();
}
return chain.proceed(request);
}
}

使用便携式网址2和匕首2的动态网址

您可以使用 unscopedprovision 方法实例化新对象。

@Provides
LoginAPI provideAPI(Gson gson, OkHttpClient client, BaseUrlHolder baseUrlHolder) {
Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)
.client(client)
.baseUrl(baseUrlHolder.get())
.build();
return retrofit.create(LoginAPI.class);
}


@AppScope
@Provides
BaseUrlHolder provideBaseUrlHolder() {
return new BaseUrlHolder("https://www.default.com")
}

public class BaseUrlHolder {
public String baseUrl;


public BaseUrlHolder(String baseUrl) {
this.baseUrl = baseUrl;
}


public String getBaseUrl() {
return baseUrl;
}


public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
}

现在可以通过从组件获取 baseUrlHolder 来更改基本 URL

App.appComponent.getBaseUrlHolder().set("https://www.changed.com");
this.loginApi = App.appComponent.getLoginApi();

对于最新的卢克菲特库,您可以简单地使用单例实例并使用 retrofitInstance.newBuilder().baseUrl(newUrl)对其进行更改。不需要创建另一个实例。

这可能有点晚,但是 Retrofit允许您在使用 @Url注释进行网络调用时使用动态 URL。 我还使用 Dagger2在我的存储库中注入 Retrofit实例,这个解决方案对我来说工作得很好。

这将使用基 URL

由您提供,同时创建的实例逆转。

@GET("/product/123")
fun fetchDataFromNetwork(): Call<Product>

这会忽略基本 url

并使用您将在运行时提供此调用的 URL。

@GET()
fun fetchDataFromNetwork(@Url url : String): Call<Product> //

这招在 Kotlin 很管用

class HostSelectionInterceptor: Interceptor {


override fun intercept(chain: Interceptor.Chain): Response {


var request = chain.request()


val host: String = SharedPreferencesManager.getServeIpAddress()


val newUrl = request.url().newBuilder()
.host(host)
.build()


request = request.newBuilder()
.url(newUrl)
.build()


return chain.proceed(request)
}


}

将拦截器添加到 OkHttpClient 构建器

val okHttpClient = OkHttpClient.Builder()
.addInterceptor(HostSelectionInterceptor())
.cache(null)
.build()

请查看我的工作区的匕首动态网址。

步骤1: 创建一个拦截器

import android.util.Patterns;


import com.nfs.ascent.mdaas.repo.network.ApiConfig;


import java.io.IOException;


import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;


public class DomainURLInterceptor implements Interceptor {


@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();


String requestUrl = original.url().toString();
String PROTOCOL = "(?i:http|https|rtsp)://";
String newURL = requestUrl.replaceFirst(PROTOCOL, "")
.replaceFirst(Patterns.DOMAIN_NAME.toString(), "");
newURL = validateBackSlash(newURL) ? ApiConfig.BASE_URL.concat(newURL) : newURL.replaceFirst("/", ApiConfig.BASE_URL);
original = original.newBuilder()
.url(newURL)
.build();


return chain.proceed(original);
}


private boolean validateBackSlash(String str) {
if (!str.substring(str.length() - 1).equals("/")) {
return true;
}
return false;
}


}

第二步:

在模块中添加新创建的拦截器

    @Provides
@Singlton
DomainURLInterceptor getChangeURLInterceptor() {
return new DomainURLInterceptor();
}

第三步: 将拦截器添加到 HttpClient 拦截器列表中

    @Provides
@Singlton
OkHttpClient provideHttpClient() {
return new OkHttpClient.Builder()
.addInterceptor(getChangeURLInterceptor())
.readTimeout(ApiConfig.API_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.connectTimeout(ApiConfig.API_CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.build();
}

第四步:

    @Provides
@Singlton
Retrofit provideRetrofit() {
return new Retrofit.Builder()
.baseUrl(ApiConfig.BASE_URL) // this is default URl,
.addConverterFactory(provideConverterFactory())
.client(provideHttpClient())
.build();
}

注意: 如果用户必须从设置中更改 BaseURL,请记住使用以下方法验证新创建的 URL:

    public final static boolean isValidUrl(CharSequence target) {
if (target == null) {
return false;
} else {
return Patterns.WEB_URL.matcher(target).matches();
}
}