cool hit counter Resolve Retrofit multiple BaseUrl and dynamically change BaseUrl at runtime?_Intefrankly

Resolve Retrofit multiple BaseUrl and dynamically change BaseUrl at runtime?

Original article address:


Hello, I'm... JessYan As a person who likes to explore new solutions, I'm not sure what to do. previous article in,shows you how you can upload and download with a single line of code and Glide Progress Monitoring, And now for another much-anticipated item of issues of solution, The problem originated in MVPArms of an Issues , of course, using Retrofit When multiple BaseUrl and dynamically switching BaseUrl are two requirements that are often discussed elsewhere, then here are my thoughts and solutions

Github : you of Star I'm the one who insisted. of power ✊


Demand emerges of scenario

Some of you may have already encountered these two requirements in your daily development, but in order to let some of you who have not encountered these scenarios before, you can also read this article, so first mention it in the front

several BaseUrl of Demand scenarios

If the project is aggregated App , compare Such as some news and information clients like, Possible data sources from multiple platforms, compare as said intimate knowledge ah, Douban, PRC social networking website ah, Today's headlines., So this would involve multiple BaseUrl

If the project makes usefulness To multiple triparty service providers, compare As the picture of Retrieval makes usefulness To a service provider, documents of storage also makes usefulness To another service provider, This one will also exist a App There are multiple BaseUrl

dynamic change BaseUrl of Demand scenarios

If the project of BaseUrl will be in App At startup, the server is requested, and based on the results returned by the server, the final project BaseUrl , would involve a runtime dynamic switch BaseUrl

If one of the three service providers of the project is not fixed, maybe there will be a change, for example, the storage service is migrated from 7Niu to other cloud storage, then we will get the three service provider's information from the server in order to avoid re-packaging and re-releasing the code. BaseUrl , and then dynamically change this at runtime BaseUrl


Actually, it's official. Api Solutions have long been available to support multiple BaseUrl As well as dynamically changing the BaseUrl at runtime, there are also many popular solutions

<a name="1"></a>

Official Static solution

familiarity with Retrofit developers should know @Get , @Post These are marked to each interface method of Annotations can not only pass relative paths, You can also pass the full path, This way we can do it differently interfaces Use different BaseUrl , thus achieving the goal of using multiple BaseUrl of need, But the note on the of The value can only be Final The constants cannot be changed dynamically, so I call this solution a static solution

<a name="2"></a>

Official Dynamic Solutions

familiarity with Retrofit developers are equally aware of the @Url This is marked on each interface method parameter of explanatory note, It can pass the full path as a parameter into the interface as a per request of Url address, Each time the interface is requested, a different of Full path as a parameter, thus achieving support for multiple BaseUrl and dynamic changes at runtime BaseUrl So many interfaces requesting images and other resources are using this solution (eek, it looks like this official solution doesn't solve both of the problems I mentioned, don't worry, read later first!)

<a name="3"></a>

Common folk solutions

I've seen a lot of open source before of polymerization App Source code, like some integration intimate knowledge , Douban, PRC social networking website , Gank of data from multiple platforms such as App , Because the respective platforms of Different domain names, So most of these types of App will create a separate Retrofit object, i.e., a different BaseUrl Use different Retrofit object to create the ApiService Make a request, This way simply adding a different of BaseUrl , that would need to recreate a new of Retrofit targets

This can also be done simultaneously, supporting multiple BaseUrl and dynamic changes at runtime BaseUrl These two needs, But with a personal of viewpoint, Create multiple other configuration properties identical, merely BaseUrl different Retrofit targets, Too much of a waste of resources

<a name="4"></a>

The Folk Bull Solution

I stumbled across one earlier Retrofit Defenders, Square The company's bull's solution , is used to solve the problem of dynamically changing the runtime BaseUrl It's actually a semi-official solution.

When it comes to this solution, I have to tell an interesting story, actually before Retrofit default is to support dynamic changes at runtime BaseUrl of, There used to be a program called BaseUrl The interface of the Retrofit.Builder#baseUrl(BaseUrl) The method was then passed of The parameter is this BaseUrl , instead of the current HttpUrl , there is a method inside this interface that returns HttpUrl ,that's when it's time to just achieve BaseUrl back, Dynamically changing this method of return value, Dynamic changes can then be achieved BaseUrl

But this bull thinks so of Unsafe practices, So mention a Pull Requests Delete this. BaseUrl interface, merge usefulness on top of of solution alternative, And dear. of JakeWharton Agreed with him. of viewpoint, and merged this PR That's how we got here. of Retrofit.Builder#baseUrl(HttpUrl) This can't be changed dynamically BaseUrl of Api

usefulness Retrofit For those of you who are old enough to know, there used to be one of these. Api, I mean, later. of Why is the version gone?, It was destroyed by this man.

This option is also the use of Interceptor interceptors, dynamically changing each Request of Url thus enabling dynamic changes BaseUrl But he can't support this solution for more than BaseUrl As long as... host Set it until the next change. Host prior to, afterwards of all Request All must make usefulness the same Host There are some drawbacks that we will analyze later.

Several programmes of right compare analysis with

Phasing out of the system containing obvious defects of options

4 1 programme in, I'll start by eliminating of even Common folk solutions , It has been made clear earlier that I of viewpoint, Because I personally think creating multiple other configuration properties exactly the same, merely BaseUrl different Retrofit targets, Too much of a waste of resources, So even if he could satisfy me. of All requirements, unless it's true of No better. of solution, I wouldn't have chosen it otherwise. of

Of the three remaining options , Official Static solution Can only solve, 2 of the requirements to support multiple BaseUrl , and for dynamic changes BaseUrl , Due to the annotation of Value It can only be a constant, so there is nothing that can be done about this requirement (both requirements are satisfied to make it feasible)

Who is the best solution?

Actually, it was stated earlier Official Dynamic Solutions It is already possible to achieve multiple simultaneous BaseUrl and runtime dynamic changes BaseUrl So why don't I just go with this option and continue the analysis?

The answer is also very simple, I think this program, although flexible, but flexible but it brings it to the use of cumbersome, each interface each call must be passed into the full path as a parameter, not only cumbersome and interface a number of bad management

that The Folk Bull Solution Is it possible? But I already said earlier that this doesn't work, huh?

This solution can support dynamic switching at runtime though BaseUrl But it is handled globally, and once used, it changes all the requested Url , so it doesn't support multiple BaseUrl

And scarier. of be, Not only does this option not support multiple BaseUrl , but also affects Official Static solution harmony Official Dynamic Solutions These two support multiple BaseUrl solution, because no matter what full path you declare in the annotation, it's Interceptor interceptor, both force the request's Url Change it to this. of BaseUrl , so this option is destined for only one BaseUrl However, items that require dynamic change

Wouldn't that make all 4 solutions unfeasible? What's taking so long?

Total elimination of the programme? Meeting adjourned?

Wait, wait, wait., Although I stand in my of perspectives, Pass clear-language in refer to of All existing of solution

But think about it., If perfection already exists online of solution, that What's the point of me still writing this article? It must not be to my satisfaction. of solution, I'm the one who's going to fix it and share it., After all, I am a reluctant writer of repetitive content of young people with promise As long as... I wrote it. of The content is sure to teach everyone different Knowledge III ✊, Or else you'll be ruining your own brand.

All right, enough teasing, let's go!

Don't worry, there's more!

Although there are already of solution proper in I didn't find anything that satisfied me. of, But in Problems encountered time, Calm analysis of existing solution It's necessary. of, Understanding those who came before us of It is only after thinking that the whole issue will be understood more thoroughly, me of Many articles are also based on the analysis of harmony Solution thinking is the main, give a man a fish and you feed him for a day; teach a man fish and you feed him for a lifetime, So I won't tell you the answer directly, First a wave of analysis, clarify the way of thinking

No, it's in the analysis. The Folk Bull Solution time, Although in the end it turns out it's not what you want of solution, But as someone who thinks outside the box. of me, Another bright idea., With the help of the original solution A change like this above is not feasible You got it?

How can the original programme be improved?

on top of of The analysis has spoken. The Folk Bull Solution , can be found at Interceptor The interceptor sets a global Host(Host can be understood as BaseUrl) , the interceptor will force this Host is applied to all requests, changing the request's original Url , which results in the existence of only one simultaneous Host

So I was thinking., Will this only of Host variable to a collection, to store multiple Host , In the case of bringing different of Host applied to different requests, it is possible to support multiple BaseUrl

Practical ideas

do as one says, So I built a global one myself of Containers come storage several Host ¶ so that I can be in ¶ App Runtime of any time, Add anywhere you want, revise, Delete Host

Problems encountered

But here's the problem, I want to put different Host applied to different requests, but how do I know what requests need what Host Every request always has to be marked so I know what he needs. Host bar (loanword) (serving drinks, or providing Internet access etc)

So I was thinking. Retrofit What's the way? , can be found at Add a different to each request before requesting of String tag, So I'm natural of thought of it Header ,Retrofit Just in time. @Headers This annotation, which can be added to each interface method to customize the Header

Solving the hard part again

I give the need for a different BaseUrl interface method to add a custom Header , to indicate the number of Host of Name ¶ And this ¶ Name corresponding of The value is Host , but the value is not in the @Headers in Is specified of, It can be changed dynamically of

storage Host The container for this is a Map , key, that's it. Name The value is... Host Each time an interceptor intercepts a request, it determines whether the request has this custom Header, have of talk, Get this. Header in put a sign on sth explaining or calling attention to of Name , and then use this Name , go to (a place) that size storage Host of security situation Map in get(name) , get the corresponding Host And then applied to the request isn't that reaching support for multiple BaseUrl You got it?

If you want to dynamically change a Host It's also easy to put a new Host alike of Name put(name) Into this global Map When the time comes for the interceptor, use this. Name get(name) Come out of value, it's already the latest in a long way since the change of Host , after putting this Host Apply to the request not to reach dynamic change BaseUrl You got it?

No, both needs are met at the same time!

Optimization options

This program is a two-step process that gives a different approach to what is needed. BaseUrl The request settings for the Header (Want to use Retrofit default BaseUrl interface, or use the Official Static solution, Official Dynamic Solutions (no need to set it), after managing the global container through the BaseUrl

For the kind of people who only have a BaseUrl However, for projects that require dynamic changes, the framework provides a GlobalDomain to optimize this scenario, without adding Header , just one step, to the global container put(GlobalDomain) You want to change. BaseUrl That'll do it.

compare Official Dynamic Solutions It is much simpler to pass the full path to each interface as a parameter, Official Dynamic Solutions Destined for the kind of dynamic change that only one or two need BaseUrl interfaces


Above of solution, It has been optimized and encapsulated as a tripartite library and uploaded to Jcenter , for your convenience.

This solution is mainly suitable for those who need to have multiple BaseUrl and dynamic changes BaseUrl projects, Or just one BaseUrl But it needs to be changed dynamically BaseUrl projects

If for just a few more BaseUrl No dynamic change required BaseUrl projects, In fact usefulness Official Static solution It is enough, but I still recommend using my solution, because the requirements are subject to change, if once you want to add dynamic changes BaseUrl of need, Dynamic switching is required Production environment harmony The development environment , that What to do then, Change each interface annotation one by one inside of Full path?

Github : See the demo for details, remember Star !

Hello My name is Jessyan, if you like my articles, you can follow me on the following platforms

-- The end

1、6 Principles of Faceted Object Design 6 The Dimity Principle
2、Spring SpringBoot and TestNG Testing Guide TestPropertySource
3、JavaUsing annotations and reflection to implement aquot low versionquot of dependency injection
4、Database transactions and isolation levels
5、Python Security From SSRF to Command Execution Fiasco

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送