中http请求爆发access,swagger原理分析与利用进度中蒙受的坑

在api项目中 本地品种不可能访问服务器api

在Android代码中,我们偶尔会采Nabi我们在AndroidManifest中设置的android:minSdkVersion版本更加高的法子,此时编写翻译器会提示警示,

浅谈springfox-swagger原理分析与应用进度中碰到的坑,

中http请求爆发access,swagger原理分析与利用进度中蒙受的坑。swagger简介

swagger确实是个好东西,能够跟据业务代码自动生成相关的api接口文书档案,特别用于restful风格中的项目,开发人士大约能够绝不特别去爱护rest
api,那几个框架能够活动为您的事情代码生成restfut风格的api,而且还提供相应的测试界面,自动展现json格式的响应。大大便利了后台开发职员与前者的联系与联调开销。

springfox-swagger简介

签于swagger的有力功效,java开源界大牌spring框架快捷跟上,它足够利用自已的优势,把swagger集成到温馨的档次里,整了3个spring-swagger,后来便演化成springfox。springfox本身只是利用本身的aop的特色,通过plug的措施把swagger集成了进来,它自己对作业api的变动,依然依靠swagger来达成。

至于这几个框架的文书档案,网上的资料比较少,超越百分之五十是入门级的大致利用。本人在合龙这么些框架到祥和项指标长河中,碰着了成都百货上千坑,为了化解那一个坑,作者只得扒开它的源码来看个究竟。此文,正是记述本身在动用springfox进程中对springfox的壹对知道以及须要专注的地点。

springfox大概原理

springfox的大概原理正是,在类型运维的过种中,spring上下文在早先化的历程,框架自动跟据配置加载1些swagger相关的bean到当前的前后文中,并活动扫描系统中大概须要生成api文书档案那么些类,并转移对应的新闻缓存起来。假如项目MVC控制层用的是springMvc那么会自行扫描全部Controller类,跟据那么些Controller类中的方法生成对应的api文档。

因自己的档次正是SpringMvc,所以此文就以Srping
mvc集成springfox为例来探究springfox的运用与原理。

SpringMvc集成springfox的步骤

先是,项目必要参预以下多个依靠:

<!-- sring mvc依赖 -->

   <dependency>

     <groupId>org.springframework</groupId>

     <artifactId>spring-webmvc</artifactId>

     <version>4.2.8.RELEASE</version>

   </dependency>

<!-- swagger2核心依赖 -->

   <dependency>

     <groupId>io.springfox</groupId>

     <artifactId>springfox-swagger2</artifactId>

     <version>2.6.1</version>

   </dependency>

   <!-- swagger-ui为项目提供api展示及测试的界面 -->

   <dependency>

     <groupId>io.springfox</groupId>

     <artifactId>springfox-swagger-ui</artifactId>

     <version>2.6.1</version>

   </dependency>

下面八个依靠是项目集成springmvc及springfox最基本的依靠,其它的依赖那里大致。当中第3个是springmvc的中坚依靠,第四个是swagger重视,第五个是界面相关的借助,那个不是必须的,固然您不想用springfox自带的api界面包车型地铁话,也得以不用那么些,而其它本身写壹套适合本人项指标界面。参加这多少个依靠后,系统后会自动进入1些跟springfox及swagger相关jar包,笔者总结看了一下,主要有以下那样多少个:

springfox-swagger2-2.6.1.jar

swagger-annotations-1.5.10.jar

swagger-models-1.5.10.jar

springfox-spi-2.6.1.jar

springfox-core-2.6.1.jar

springfox-schema-2.6.1.jar

springfox-swagger-common-2.6.1.jar

springfox-spring-web-2.6.1.jar

guava-17.0.jar

spring-plugin-core-1.2.0.RELEASE.jar

spring-plug-metadata-1.2.0.RELEASE.jar

spring-swagger-ui-2.6.1.jar

jackson-databind-2.2.3.jar

jackson-annotations-2.2.3.jar

地方是小编经过目测觉得springfox可能须要的jar,也许没有完全例出springfox所需的富有jar。从上面jar能够见见pringfox除了依靠swagger之外,它还索要guava、spring-plug、jackson等正视包(注意jackson是用以生成json必须的jar包,借使项目里笔者并未有出席这一个依靠,为了集成swagger的话不能够不附加再进入那个依靠)。

springfox的简短利用

万叁只用springfox的暗许的安顿来说,与springmvc集成起来格外简单,只要写二个好像于以下代码的类放到您的花色里就行了,代码如下:

@Configuration

@EnableWebMvc

@EnableSwagger2

publicclass ApiConfig {}

瞩目到,上边是2个空的java类文件,类名能够轻易钦命,但必须投入上述类中标明的@Configuration、@EnableWebMvc、@EnableSwagger2四个申明,这样就完结了springmvc与springfox的着力集成,有了四个评释,项目运转后就足以间接用接近于以下的地方来查阅api列表了:

这着实是一个很神奇的功力,不难的多少个注明,系统就自动展现出档次里全部Controller类的有着api了。以往,大家就这几个布局类入手,简单解析它的原理。那个类中一向不别的代码,很明朗,八个注解起了重点的意义。在那之中@Configuration申明是spring框架中自小编就有的,它是2个被@Component元申明标识的笺注,所以有了这些申明后,spring会自动把这些类实例化成1个bean注册到spring上下文中。首个表明@EnableWebMvc故名思义,正是启用srpingmvc了,在Eclipse中点到这一个申明里面大约看一下,它就是因此元表明@Import(DelegatingWebMvcConfiguration.class)往spring
context中塞入了2个DelegatingWebMvcConfiguration类型的bean。笔者想,那么些类的指标应该正是为swagger提供了部分springmvc方面包车型客车配备吧。第多个评释:@EnableSwagger二,看名字应该能够想到,是用来集成swagger
2的,他通过元表明:@Import({Swagger二DocumentationConfiguration.class}),又引进了一个Swagger二DocumentationConfiguration类型的布局bean,而这一个正是Swagger的骨干配置了。它里面包车型大巴代码如下:

@Configuration
@Import({ SpringfoxWebMvcConfiguration.class, SwaggerCommonConfiguration.class })
@ComponentScan(basePackages = {
 "springfox.documentation.swagger2.readers.parameter",
  "springfox.documentation.swagger2.web",
  "springfox.documentation.swagger2.mappers"
})

publicclassSwagger2DocumentationConfiguration {
 @Bean
 public JacksonModuleRegistrar swagger2Module() {
  returnnewSwagger2JacksonModule();
 }
}

其一类底部通过1些阐明,再引进SpringfoxWebMvcConfiguration类和SwaggerCommonConfiguration类,并透过ComponentScan注明,自动扫描springfox
.swagger二相关的的bean到spring
context中。那里,作者最感兴趣的是SpringfoxWebMvcConfiguration这么些类,这一个类作者猜应该便是springfox集成mvc比较基本的布置了,点进入,看到以下代码:

@Configuration
@Import({ModelsConfiguration.class })
@ComponentScan(basePackages = {
  "springfox.documentation.spring.web.scanners",
"springfox.documentation.spring.web.readers.operation","springfox.documentation.spring.web.readers.parameter","springfox.documentation.spring.web.plugins","springfox.documentation.spring.web.paths"
})

@EnablePluginRegistries({ DocumentationPlugin.class,
  ApiListingBuilderPlugin.class,
  OperationBuilderPlugin.class,
  ParameterBuilderPlugin.class,
  ExpandedParameterBuilderPlugin.class,
  ResourceGroupingStrategy.class,
  OperationModelsProviderPlugin.class,
  DefaultsProviderPlugin.class,
  PathDecorator.class
})
publicclassSpringfoxWebMvcConfiguration {}

那一个类中下边包车型客车代码,无非就是经过@Bean证明再参预一些新的Bean,笔者对它的志趣不是相当大,作者最感兴趣的是尾部通过@EnablePluginRegistries到场的那几个东西。springfox是基于spring-plug的体制结合swagger的,spring-plug具体是怎么落到实处的,作者近来还不曾时间去研讨spring-plug的原理。但在下文仲提到本身写1个plug插件来扩充swagger的效益。下边通过@EnablePluginRegistries参加的plug中,还并没有时间去看它全体的代码,近期自己看过的代码首要有ApiListingBuilderPlugin.class,
OperationBuilderPlugin.class,ParameterBuilderPlugin.class,
ExpandedParameterBuilderPlugin.class,

首先个ApiListingBuilderPlugin,它有七个落实类,分别是ApiListingReader和SwaggerApiListingReader。在那之中ApiListingReader会自动跟据Controller类型生成api列表,而SwaggerApiListingReader会跟据有@Api表明标识的类生成api列表。OperationBuilderPlugin插件就是用来生成现实api文书档案的,那些类别的插件,有为数不少过多兑现类,他们分别分工,各做各的事务,具体小编从没仔细去看,只关切了内部2个达成类:OperationParameterReader,那个类是用来读取api参数的Plugin。它凭借于ModelAttributeParameterExpander工具类,能够将Controller中接口方法参数中国和北美洲简要类型的命令对像自动分析它里面包车型大巴习性得出包罗全部属性的参数列表(那里存在三个可能会并发极端递归的坑,下文有介绍)。而ExpandedParameterBuilderPlugin插件,首假使用以扩大接口参数的部分作用,比如判断这几个参数的数据类型以及是或不是为那么些接口的必须参数等等。总体上说,整个springfox-swagger内部其实是由那壹种类的plug转运起来的。他们在系统运行时,就被调起来,有个别用来围观出接口列表,有个别用来读取接口参数等等。他们共同的目地便是把系统中兼有api接口都围观出来,并缓存起来供用户查看。那么,那1多元表plug到底是何等被调起来的,它们的履行入口倒底在哪?

  
大家把注意点放到上文SpringfoxWebMvcConfiguration那一个类代码底部的ComponentScan表明内容上来,那1段注明中围观了二个叫springfox.documentation.spring.web.plugins的package,那一个package在springfox-spring-web-2.六.一.jar中得以找到。那个package下,大家发现有八个尤其大旨的类,那正是DocumentationPluginsManager和DocumentationPluginsBootstrapper。对于第三个DocumentationPluginsManager,它是一个从没有过兑现任何接口的bean,但它当中有过多PluginRegistry类型的质量,而且都以由此@Autowired注脚把属性值注入进来的。接合它的类名来看,很简单想到,那些便是治本全数plug的二个管理器了。很好通晓,因为ComponentScan评释的布局,全部的plug实例都会被spring实例化成1个bean,然后被注入到那个DocumentationPluginsManager实例中被合并管理起来。在那些package中的另叁个器重的类DocumentationPluginsBootstrapper,看名字就足以猜到,他大概就是plug的启航类了。点进入看现实时就能够窥见,他果然是三个被@Component标识了的组件,而且它的构造方法中流入了正要描述的DocumentationPluginsManager实例,而且最重大的,它还达成了SmartLifecycle接口。对spring
bean生命周期有所精通的人的都知道,那几个组件在被实例化为一个bean纳入srping
context中被管制起来的时候,会活动调用它的start()方法。点到start()中看代码时就会发觉,它有一行代码scanDocumentation(buildContext(each));正是用来扫描api文书档案的。进一步跟踪那个点子的代码,就足以窥见,这些主意最后会通过它的DocumentationPluginsManager属性把具备plug调起一起扫描整个种类并生成api文书档案。扫描的结果,缓存在DocumentationCache那个类的二个map属性中。

  
以上就是,srpingMvc整合springfox的大致原理。它根本是经过EnableSwagger二注脚,向srping
context注入了壹二种bean,并在系统运维的时候自动扫描系统的Controller类,生成对应的api信息并缓存起来。其它,它还注入了有些被@Controller评释标识的Controller类,作为ui模块访问api列表的进口。比如springfox-swagger二-2.陆.一.jar包中的Swagger2Controller类。这一个Controller正是ui模块中用来走访api列表的界面地址。在做客

打探了springfox的原理,上边来探视springfox使用进程中,我碰着的怎么着坑。

springfox第一大坑:配置类生成的bean必须与spring
mvc共用同1个上下文。

前文描述了,在springmvc项目中,集成springfox是只要在档次写一个之类的未有别的业务代码的不难安排类就足以了。

@Configuration
@EnableWebMvc
@EnableSwagger2
publicclass ApiConfig {
}

因为@Configuration注明的成效,spring会自动把它实例化成二个bean注入到上下文。但切记要小心的二个坑便是:那几个bean所在的上下文必须跟spring
mvc为同三个上下文。怎么解理呢?因为在事实上的spring
mvc项目中,常常有多少个上下文,一个是跟上下文,另3个是spring
mvc(它是跟上下文的子上下文)。个中跟上下文是正是web.xml文件中跟spring相关的拾叁分org.springframework.web.context.request.RequestContextListener监听器,加载起来的上下文,平日大家会写一个叫spring-contet.xml的安排文件,那之中的bean最后会伊始化到跟上下文中,它至关心珍视要归纳系统之中的service,dao等bean,也包罗数据源、事物等等。而另1个上下文是正是spring
mvc了,它通过web.xml中跟spring
mvc相关的要命org.springframework.web.servlet.DispatcherServlet加载起来,他日常有二个安排文件叫spring-mvc.xml。大家在写ApiConfig这么些类时,假若控制用@Configuration注脚来加载,那么就无法不保证那些类所在的路子刚幸亏springmvc的component-scan的配置的base-package范围内。因为在ApiConfig在被spring加载时,会注入1列体系的bean,而这个bean中,为了能自动扫描出富有Controller类,某些bean必要重视于SpringMvc中的1些bean,假使项目把Srpingmvc的上下文与跟上下文分开来,作为跟上下文的子上下文的话。假使十分的大心让那几个ApiConfig类型的bean被跟上文加载到,因为root
context中从不spring mvc的context中的那么些配置类时就会报错。

事实上,小编并不赞同通过@Configuration注明来布局Swagger,因为本身觉得,Swagger的api作用对于生产项目以来是无所谓的。大家Swagger往往是用以测试环境供项近日端团队支付或供其他种类作接口集成使上。系统上线后,十分大概在生产系统上隐藏这个api列表。
但借使安顿是由此@Configuration注明写死在java代码里的话,那么上线的时候想去掉那么些功效的时候,那就窘迫了,不得不修改java代码重新编写翻译。基于此,小编引入的3个措施,通过spring最古板的xml文件配置格局。具体做法正是去掉@Configuration注脚,然后它写2个好像于<bean
class=”com.jad.web.mvc.swagger.conf.ApiConfig”/>那样的bean配置到spring的xml配置文件中。在root
context与mvc的context分开的档次中,直接配备到spring-mvc.xml中,这样就保证了它跟springmvc
的context一定处于同八个context中。

springfox第一大坑:Controller类的参数,注意幸免出现Infiniti递归的动静。

Spring
mvc有强有力的参数绑定机制,可以自行把请求参数绑定为二个自定义的指令对像。所以,很多开发人员在写Controller时,为了偷懒,直接把二个实体对像作为Controller方法的多个参数。比如下边那么些示例代码:

@RequestMapping(value = "update")
public String update(MenuVomenuVo, Model model){
}

那是大多数程序员喜欢在Controller中写的改动有个别实体的代码。在跟swagger集成的时候,那里有贰个大坑。借使MenuVo这么些类中具有的天性都是基本类型,那幸好,不会出什么样难点。但若是这几个类里面有部分别样的自定义类型的性质,而且以此特性又直白或直接的存在它自身类型的脾气,那就会出难点。例如:假设MenuVo这么些类是菜单类,在这些类时又富含MenuVo类型的三天质量parent代表它的父级菜单。这样的话,系统运行时swagger模块就因无法加载这些api而直接报错。报错的由来即便,在加载那些法子的经过中会解析那个update方法的参数,发现参数MenuVo不是不难类型,则会自动以递归的方法诠释它有着的类属性。那样就很不难陷入极度递归的死循环。

为了化解这一个难点,小编当下只是自个儿写了二个OperationParameterReader插件完成类以及它依靠的ModelAttributeParameterExpander工具类,通过配备的主意替换掉到srpingfox原来的那四个类,偷梁换柱般的把参数解析那几个逻辑替换掉,并逃脱Infiniti递归。当然,这一定于是1种修改源码级其余措施。作者当下还平昔不找到解决这几个题材的更周全的不2秘诀,所以,只可以建议大家在用spring-fox
Swagger的时候尽量制止那种非常递归的动静。终归,这不符合springmvc命令对像的正式,springmvc参数的授命对像中最佳只包罗不难的中坚类型属性。

springfox第三大坑:api分组相关,Docket实例无法延缓加载

springfox默许会把拥有api分成一组,那样经过类似于:

@EnableWebMvc
@EnableSwagger2
publicclass ApiConfig {
@Bean
 public Docket customDocket() {
    return newDocket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
  }
}

上述代码中经过@Bean注入贰个Docket,那么些布局并不是必须的,如果未有这些布局,框架会融洽生成二个默许的Docket实例。这一个Docket实例的成效正是点名全体它能管住的api的公共消息,比如api版本、笔者等等基本音讯,以及内定只列出怎么样api(通过api地址或注明过滤)。

Docket实例可以有两个,比如如下代码:

@EnableWebMvc
@EnableSwagger2
publicclass ApiConfig {
@Bean
 public Docket customDocket1() {
    return newDocket(DocumentationType.SWAGGER_2)
.groupName("apiGroup1").apiInfo(apiInfo()).select()

.paths(PathSelectors.ant("/sys/**"));

  }

@Bean
 public Docket customDocket2() {
    return newDocket(DocumentationType.SWAGGER_2)
.groupName("apiGroup2").apiInfo(apiInfo())
.select()
.paths(PathSelectors.ant("/shop/**"));
  }
}

当在品种中安插了多少个Docket实例时,也就能够对api实行分组了,比如上边代码将api分为了两组。在那种景况下,必须给每壹组钦定三个两样的名目,比如下边代码中的”apiGroup1″和”apiGroup二”,每1组能够用paths通过ant风格的地方表明式来钦定哪一组管理哪些api。比如下边配置中,第三组管理地点为/sys/初始的api第一组管理/shop/发轫的api。当然,还有好多其余的过滤格局,比如跟据类表明、方法表明、地址正则表明式等等。分组后,在api
列表界面右上角的下拉精选中就足以选取不一致的api组。那样就把品种的api列表分散到分歧的页面了。那样,即方便管理,又不致于页面因须要加载太多api而假死。

不过,同使用@Configuration一样,作者并不支持选取@Bean来安排Docket实例给api分组。因为如此,同样会把代码写死。所以,小编引入在xml文件中自个儿配置Docket实例完毕这一个类似的功力。当然,思考到Docket中的众多性质,直接配置bean比较麻烦,能够友善为Docket写一个FactoryBean,然后在xml文件中安排FactoryBean就行了。然则将Docket配置到xml中时。又会遭逢五个大坑,就那是,spring对bean的加载方式暗中同意是延迟加载的,在xml中央直机关接配备那一个Docket实例Bean后。你会意识,未有一点意义,页面左上角的下拉列表中跟本未有您的分组项。

本条题材曾干扰过自家一点个小时,后来凭经验估摸出只怕是因为sping
bean默许延迟加载,这些Docket实例还没加载到spring
context中。实事阐明,小编的推测是对的。笔者不知道那究竟springfox的四个bug,还是因为作者跟本不应当把对Docket的配置从原来的java代码中搬到xml配置文件中来。

springfox其余的坑:springfox还有个别其余的坑,比如@ApiOperation注明中,假使不钦点httpMethod属性具体为有些get或post方法时,api列表中,会它get,post,delete,put等富有办法都列出来,搞到api列表重复的太多,很丑。其它,还有在测试时,境遇登录权限难点,等等。这一批堆的相比较便于消除的小坑,因为篇幅有限,笔者就不多说了。还有诸如@Api、@ApiOperation及@ApiParam等等表明的用法,网上海人民广播广播台湾大学那下面的文书档案,小编就不重复了。

上述就是本文的全体内容,希望对大家的读书抱有支持,也期待大家多多匡助帮客之家。

swagger简介
swagger确实是个好东西,可以跟据业务代码自动生成相关的api接口文书档案,特别…

    在当下的主流架构中,大家愈多的看到web
Api的存在,小巧,灵活,基于Http协议,使它在更为多的微服务项目可能移动项目充当很好的service
endpoint。

美高梅开户网址 1

解决措施是在艺术上加上@SuppressLint(“NewApi”)或然@TargetApi()。

问题

    以Asp.Net Web Api 为例,随着工作的恢弘,产品的迭代,我们的web
api也在随后变动,很多时候会出现多少个版本共存的气象,今年大家就须要统一筹划三个支撑版本号的web
api link,比如:

原先:

如今:

美高梅开户网址 ,在大家刚设计的时候,有希望未有设想版本的难点,小编看出不少的品类都会在link后插手一个“?version=”的方法,那种措施的确能够消除难题,但对Asp.Net
Web
Api来说,进入的要么同四个Controller,大家须求在同二个Action中开始展览判断版本号,例如:

]

public class BlogsController : ApiController
{
    // GET api/<controller>
    public IEnumerable<string> Get([FromUri]string version = "")
    {
        if (!String.IsNullOrEmpty(version))
        {
            return new string[] { $"{version} blog1", $"{version} blog2" };
        }
        return new string[] { "blog1", "blog2" };
    }
}

咱俩见到大家通过判断url中的version参数进行对应的回来,为了确定保证原先接口的可用,大家需求对参数赋上私下认可值,固然能够化解大家的版本迭代难点,但随着版本的不断更新,你会意识那些Controller会越来越臃肿,维护越来越困难,因为那种修改已经严重违反了OCP(Open-Closed
Principle),最佳的艺术是不修改原先的Controller,而是新建新的Controller,放在对应的目录中(可能项目中),比如:

美高梅开户网址 2

为了不影响原本的门类,大家尽量不要转移原Controller的Namespace,除非您有丰硕的把握未有影响,不然请尽恐怕只是运动到目录。

ok,为了保险原接口的炫耀,大家须求在WebApiConfig.Register中登记帮助版本号的Route映射:

config.Routes.MapHttpRoute(
    name: "DefaultVersionApi",
    routeTemplate: "api/{version}/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

开拓浏览器依旧postman,输入原先的api url,你会意识这么的不当:

美高梅开户网址 3

那是因为web api
查找Controller的时候,只会依照ClassName举行搜索的,当出现相同ClassName的时候,就会报这一个荒唐,那时候我们就需求创造和谐的Controller
Selector,幸而微软留了一个接口给到我们:IHttpControllerSelector。然而为了同盟原先的api(某些不在我们权力限制内的api,不加版本号的那种),咱们依旧直接集成DefaultHttpControllerSelector比较好,大家给定一个平整,不承担大家版本迭代的api,就让它走原先的映照。

百度了下,查出原因

这他们之间有如何界别吧,很简单,

思路

一、项目运维的时候,先把符合条件的Controller参加到1个字典中

二、判断request,符合规则的,我们回来大家制定的controller。

美高梅开户网址 4

美高梅开户网址 5

美高梅开户网址 6

@SuppressLint(“NewApi”)屏蔽一切新api中才能选取的方法报的android
lint错误

营造属于自个儿的Selector

思路有了,那改造起来也十一分简单,前几日我们先做三个简约的,等有时光改成可配备的。

率先步,大家先创制三个Selector类,继承自DefaultHttpControllerSelector,然后初始化的时候创设贰个属于我们团结的字典:

public class VersionHttpControllerSelector : DefaultHttpControllerSelector
{
    private readonly HttpConfiguration _configuration;
    private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _lazyMappingDictionary;
    private const string DefaultVersion = "v1"; //默认版本号,因为之前的api我们没有版本号的概念
    private const string DefaultNamespaces = "WebApiVersions.Controllers"; //为了演示方便,这里就用到一个命名空间
    private const string RouteVersionKey = "version"; //路由规则中Version的字符串
    private const string DictKeyFormat = "{0}.{1}";
    public VersionHttpControllerSelector(HttpConfiguration configuration):base(configuration)
    {
        _configuration = configuration;
        _lazyMappingDictionary = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDict);
    }

    private Dictionary<string, HttpControllerDescriptor> InitializeControllerDict()
    {
        var result = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
        var assemblies = _configuration.Services.GetAssembliesResolver();
        var controllerResolver = _configuration.Services.GetHttpControllerTypeResolver();
        var controllerTypes = controllerResolver.GetControllerTypes(assemblies);

        foreach(var t in controllerTypes)
        {
            if (t.Namespace.Contains(DefaultNamespaces)) //符合NameSpace规则
            {
                var segments = t.Namespace.Split(Type.Delimiter);
                var version = t.Namespace.Equals(DefaultNamespaces, StringComparison.OrdinalIgnoreCase) ?
                    DefaultVersion : segments[segments.Length - 1];
                var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length);
                var key = string.Format(DictKeyFormat, version, controllerName);
                if (!result.ContainsKey(key))
                {
                    result.Add(key, new HttpControllerDescriptor(_configuration, t.Name, t));
                }
            }
        }

        return result;
    }
}

有了字典接下去就好办了,只须求分析request就好了,符合大家版本供给的,就从大家的字典中搜寻对应的Descriptor,假设找不到,就走暗中认可的,那里我们要求重写SelectController方法:

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
    IHttpRouteData routeData = request.GetRouteData();
    if (routeData == null)
        throw new HttpResponseException(HttpStatusCode.NotFound);

    var controllerName = GetControllerName(request);
    if (String.IsNullOrEmpty(controllerName))
        throw new HttpResponseException(HttpStatusCode.NotFound);

    var version = DefaultVersion;
    if (IsVersionRoute(routeData, out version))
    {
        var key = String.Format(DictKeyFormat, version, controllerName);
        if (_lazyMappingDictionary.Value.ContainsKey(key))
        {
            return _lazyMappingDictionary.Value[key];
        }

        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    return base.SelectController(request);
}

private bool IsVersionRoute(IHttpRouteData routeData, out string version)
{
    version = String.Empty;
    var prevRouteTemplate = "api/{controller}/{id}";
    object outVersion;
    if(routeData.Values.TryGetValue(RouteVersionKey, out outVersion))   //先找符合新规则的路由版本
    {
        version = outVersion.ToString();
        return true;
    }

    if (routeData.Route.RouteTemplate.Contains(prevRouteTemplate))  //不符合再比对是否符合原先的api路由
    {
        version = DefaultVersion;
        return true;
    }

    return false;
}

成功那一个类后,大家去WebApiConfig.Register中举行轮换操作:

config.Services.Replace(typeof(IHttpControllerSelector), new VersionHttpControllerSelector(config));

ok,再度打开浏览器,输入 和
,那时应该能来看科学的履行:

美高梅开户网址 7

美高梅开户网址 8

随之找到rails项目标消除措施,安装rack-cors这几个gem包

@TargetApi() 只屏蔽某一新api中才能利用的艺术报的android lint错误

写在最终

后天大家制作了二个简约符合webapi版本号更新迭代的ControllerSelector,可是还不是很周全,因为许多都以hard
code,前边笔者会做三个支撑配置的ControllerSelector放到github上。

事先一向在切磋eShopOnContrainers,近日也在切磋,可是工作的确有点忙,见谅见谅,要是大家.Net有怎么着难点要么喜欢技术交友的,都能够加QQ群:37624805四

具体方法如下:

举个例证,有些方法中利用了api九新投入的方法,而项目设置的android:minSdkVersion=八,此时在点子上加@SuppressLint(“NewApi”)

Gemfile中加入

和@TargetApi(Build.VERSION_CODES.GINGERBREAD)都得以,以上是通用的事态。

gem 'rack-cors', :require => 'rack/cors'

而当您在此方式中又引述了一个api11才参与的不2诀窍时,@TargetApi(Build.VERubiconSION_CODES.GINGERBREAD)注解的法子又报错了,而

  终端运转  bundle

@SuppressLint(“NewApi”)不会报错,那便是分别。

在application.rb中投入以下代码

 

config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins '*'
        resource '*',
                 :headers => :any,
                 :methods => :any,
                 :expose => ['access-token', 'expiry', 'token-type', 'uid', 'client']
      end
 end

自然,不管你利用了哪位注脚,效率只是是屏蔽android
lint错误,所以在格局中还要判断版本做区别的操作,比如:

 重启项目即可消除此难点

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {  
            //  
} else {// Pre GINGERBREAD  
            //  
}  

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图