【4858.com】中http请求产生access,swagger原理分析与运用进度中遇见的坑

By admin in 4858.com on 2019年3月26日

在api项目中 本地品种不大概访问服务器api

在Android代码中,我们有时候会使用比大家在AndroidManifest中安装的android:minSdkVersion版本更高的点子,此时编写翻译器会唤醒警示,

【4858.com】中http请求产生access,swagger原理分析与运用进度中遇见的坑。浅谈springfox-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上下文在起先化的进度,框架自动跟据配置加载一些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最中央的借助,别的的借助那里大约。当中第三个是springmvc的主干依靠,第二个是swagger重视,第多少个是界面相关的注重,这一个不是必须的,假若您不想用springfox自带的api界面包车型地铁话,也得以绝不这么些,而其它本人写一套适合本人项目标界面。出席那多少个依靠后,系统后会自动进入一些跟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 {}

注意到,下面是1个空的java类文件,类名可以随意内定,但不可能不参与上述类中标注的@Configuration、@EnableWebMvc、@EnableSwagger2多个申明,那样就成功了springmvc与springfox的骨干集成,有了三个证明,项目运行后就足以一贯用类似于以下的地点来查阅api列表了:

那真的是3个很神奇的成效,简单的两个注解,系统就自动呈现出档次里有着Controller类的保有api了。今后,大家就那么些布局类动手,简单解析它的规律。那些类中从未任何代码,很扎眼,三个表明起了最主要的效果。当中@Configuration注解是spring框架中本人就有的,它是一个被@Component元注脚标识的笺注,所以有了这一个表明后,spring会自动把这些类实例化成贰个bean注册到spring上下文中。第③个注脚@EnableWebMvc故名思义,便是启用srpingmvc了,在Eclipse中式点心到那一个注脚里面大约看一下,它正是由此元表明@Import(DelegatingWebMvcConfiguration.class)往spring
context中塞入了叁个DelegatingWebMvcConfiguration类型的bean。笔者想,那几个类的目标应该就是为swagger提供了一些springmvc方面包车型客车布署吧。第八个申明:@EnableSwagger2,看名字应该能够想到,是用来集成swagger
2的,他经过元表明:@Import({Swagger2DocumentationConfiguration.class}),又引入了2个Swagger2DocumentationConfiguration类型的安插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();
 }
}

其一类尾部通过有个别诠释,再引入SpringfoxWebMvcConfiguration类和SwaggerCommonConfiguration类,并由此ComponentScan申明,自动扫描springfox
.swagger2相关的的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的规律。但在下文种提到自身写叁个plug插件来扩张swagger的效力。下边通过@EnablePluginRegistries参预的plug中,还未曾时间去看它全体的代码,方今自己看过的代码首要有ApiListingBuilderPlugin.class,
OperationBuilderPlugin.class,ParameterBuilderPlugin.class,
ExpandedParameterBuilderPlugin.class,

第三个ApiListingBuilderPlugin,它有多少个落到实处类,分别是ApiListing里德r和SwaggerApiListingReader。其中ApiListingReader会自动跟据Controller类型生成api列表,而SwaggerApiListingReader会跟据有@Api阐明标识的类生成api列表。OperationBuilderPlugin插件便是用来生成现实api文书档案的,这几个项指标插件,有好多广大落到实处类,他们分别分工,各做各的事体,具体笔者未曾仔细去看,只关注了里面一个贯彻类:OperationParameterReader,那个类是用来读取api参数的Plugin。它凭借于ModelAttributeParameterExpander工具类,能够将Controller中接口方法参数中国和欧洲大约类型的授命对像自动分析它个中的属性得出包罗全数属性的参数列表(那里存在三个或者会出现极端递归的坑,下文有介绍)。而ExpandedParameterBuilderPlugin插件,首假设用以扩张接口参数的局地意义,比如判断这些参数的数据类型以及是不是为这么些接口的总得参数等等。总体上说,整个springfox-swagger内部其实是由这一一日千里的plug转运起来的。他们在系统运维时,就被调起来,有个别用来围观出接口列表,某些用来读取接口参数等等。他们手拉手的目地正是把系统中具有api接口都围观出来,并缓存起来供用户查看。那么,这一多级表plug到底是怎么被调起来的,它们的实施入口倒底在哪?

  
大家把注意点放到上文SpringfoxWebMvcConfiguration那么些类代码底部的ComponentScan注明内容上来,这一段注明中围观了三个叫springfox.documentation.spring.web.plugins的package,那些package在springfox-spring-web-2.6.1.jar中能够找到。那么些package下,大家发现有四个要命焦点的类,那正是DocumentationPluginsManager和DocumentationPluginsBootstrapper。对于第贰个DocumentationPluginsManager,它是2个不曾落到实处任何接口的bean,但它在那之中有许多PluginRegistry类型的习性,而且都是由此@Autowired注脚把属性值注入进来的。接合它的类名来看,很不难想到,这么些正是管理全数plug的三个管理器了。很好通晓,因为ComponentScan表明的布置,全数的plug实例都会被spring实例化成一个bean,然后被注入到这几个DocumentationPluginsManager实例中被统管起来。在那几个package中的另贰个主要的类DocumentationPluginsBootstrapper,看名字就足以猜到,他也许就是plug的启航类了。点进入看现实时就可以发现,他果然是三个被@Component标识了的组件,而且它的构造方法中流入了正要描述的DocumentationPluginsManager实例,而且最注重的,它还达成了斯马特Lifecycle接口。对spring
bean生命周期有所通晓的人的都驾驭,那个组件在被实例化为3个bean纳入srping
context中被管理起来的时候,会自行调用它的start()方法。点到start()中看代码时就会发觉,它有一行代码scanDocumentation(buildContext(each));正是用来扫描api文书档案的。进一步跟踪这几个方式的代码,就足以窥见,那些方法最终会通过它的DocumentationPluginsManager属性把全数plug调起一起扫描整个系统并生成api文书档案。扫描的结果,缓存在DocumentationCache这几个类的多个map属性中。

  
以上就是,srpingMvc整合springfox的差不离原理。它根本是经过EnableSwagger2评释,向srping
context注入了一多级bean,并在系统运营的时候自动扫描系统的Controller类,生成对应的api音信并缓存起来。其它,它还注入了一些被@Controller注脚标识的Controller类,作为ui模块访问api列表的入口。比如springfox-swagger2-2.6.1.jar包中的Swagger2Controller类。这些Controller就是ui模块中用来拜访api列表的界面地址。在造访

刺探了springfox的规律,上面来看望springfox使用进度中,作者遇上的哪些坑。

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

前文描述了,在springmvc项目中,集成springfox是一旦在档次写一个之类的远非别的业务代码的大约安排类就能够了。

@Configuration
@EnableWebMvc
@EnableSwagger2
publicclass ApiConfig {
}

因为@Configuration注脚的机能,spring会自动把它实例化成三个bean注入到上下文。但切记要专注的1个坑就是:那些bean所在的上下文必须跟spring
mvc为同三个上下文。怎么解理呢?因为在实质上的spring
mvc项目中,平时有多少个上下文,四个是跟上下文,另二个是spring
mvc(它是跟上下文的子上下文)。个中跟上下文是就是web.xml文件中跟spring相关的百般org.springframework.web.context.request.RequestContextListener监听器,加载起来的上下文,平常我们会写3个叫spring-contet.xml的布署文件,这其间的bean最后会初步化到跟上下文中,它根本包蕴系统内部的service,dao等bean,也包涵数据源、事物等等。而另二个上下文是正是spring
mvc了,它通过web.xml中跟spring
mvc相关的可怜org.springframework.web.servlet.DispatcherServlet加载起来,他一般有多少个布局文件叫spring-mvc.xml。大家在写ApiConfig那一个类时,固然控制用@Configuration注明来加载,那么就亟须保障那么些类所在的途径刚辛亏springmvc的component-scan的安插的base-package范围内。因为在ApiConfig在被spring加载时,会注入一列连串的bean,而这一个bean中,为了能自动扫描出装有Controller类,某些bean供给借助于SpringMvc中的一些bean,即使项目把Srpingmvc的上下文与跟上下文分开来,作为跟上下文的子上下文的话。假设十分的大心让这么些ApiConfig类型的bean被跟上文加载到,因为root
context中并未spring mvc的context中的这几个配置类时就会报错。

实事上,作者并不赞同通过@Configuration表明来配置Swagger,因为自己觉着,Swagger的api效用对于生产品种来说是开玩笑的。大家Swagger往往是用以测试环境供项如今端团队支付或供别的类别作接口集成使上。系统上线后,很可能在生养连串上隐藏这个api列表。
但假使安顿是通过@Configuration注解写死在java代码里的话,那么上线的时候想去掉这一个效率的时候,那就难堪了,不得不修改java代码重新编写翻译。基于此,笔者引进的贰个艺术,通过spring最守旧的xml文件配置格局。具体做法正是去掉@Configuration表明,然后它写1个看似于<bean
class=”com.jad.web.mvc.swagger.conf.ApiConfig”/>那样的bean配置到spring的xml配置文件中。在root
context与mvc的context分开的品类中,直接配备到spring-mvc.xml中,那样就保险了它跟springmvc
的context一定处于同三个context中。

springfox第三大坑:Controller类的参数,注意防止出现无限递归的动静。

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

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

那是绝当先1/4程序员喜欢在Controller中写的修改某些实体的代码。在跟swagger集成的时候,那里有1个大坑。假使MenuVo那几个类中全数的性质都以宗旨项目,那幸好,不会出什么难点。但一旦这一个类里面有一部分别的的自定义类型的属性,而且以此个性又平素或直接的存在它自个儿类型的性质,那就会出难题。例如:要是MenuVo这几个类是菜单类,在这一个类时又含有MenuVo类型的叁个性格parent代表它的父级菜单。那样的话,系统运行时swagger模块就因不能加载那个api而直白报错。报错的原故就算,在加载这么些方法的进程中会解析那一个update方法的参数,发现参数MenuVo不是简单类型,则会自行以递归的法门诠释它具备的类属性。那样就很简单陷入卓殊递归的死循环。

为了缓解这么些题材,笔者当下只是自个儿写了三个OperationParameterReader插件完成类以及它借助的ModelAttributeParameterExpander工具类,通过配备的不二法门替换掉到srpingfox原来的那三个类,偷梁换柱般的把参数解析那几个逻辑替换掉,并躲开无限递归。当然,这一定于是一种修改源码级别的法子。笔者当下还并未找到消除那些题指标更宏观的点子,所以,只可以提议大家在用spring-fox
Swagger的时候尽量制止那种万分递归的情景。究竟,那不符合springmvc命令对像的标准,springmvc参数的指令对像中最棒只含有简单的骨干类型属性。

springfox第3大坑:api分组相关,Docket实例不能够推迟加载

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

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

4858.com,上述代码中经过@Bean注入1个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″和”apiGroup2″,每一组能够用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。

4858.com 1

消除措施是在情势上添加@SuppressLint(“NewApi”)只怕@TargetApi()。

问题

    以Asp.Net Web Api 为例,随着事情的壮大,产品的迭代,大家的web
api也在跟着变化,很多时候会并发八个本子共存的光景,那个时候大家就必要规划三个支撑版本号的web
api link,比如:

原先:

如今:

在大家刚设计的时候,有可能没有设想版本的难点,笔者看来众多的品种都会在link后投入三个“?version=”的主意,那种方式真的能够缓解难点,但对Asp.Net
Web
Api来说,进入的大概同3个Controller,大家供给在同2个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,放在对应的目录中(或许项目中),比如:

4858.com 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,你会发觉那样的谬误:

4858.com 3

那是因为web api
查找Controller的时候,只会依据ClassName进行搜索的,当出现相同ClassName的时候,就会报那几个荒唐,那时候咱们就须要创设自个儿的Controller
Selector,辛亏微软留了一个接口给到大家:IHttpControllerSelector。可是为了协作原先的api(有个别不在大家权力限制内的api,不加版本号的那种),大家依旧一直集成DefaultHttpControllerSelector相比好,我们给定2个条条框框,不担负大家版本迭代的api,就让它走原先的映照。

百度了下,查出原因

那她们之间有啥样界别吧,很简单,

思路

① 、项目运行的时候,先把符合条件的Controller参与到1个字典中

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

4858.com 4

4858.com 5

4858.com 6

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

营造属于自身的Selector

思路有了,那改造起来也万分不难,今日大家先做二个简单易行的,等有时光改成可配备的。

率先步,大家先创设五个Selector类,继承自DefaultHttpControllerSelector,然后开端化的时候创造3个属于大家同舟共济的字典:

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,再一次打开浏览器,输入 和
,这时应该能来看科学的实施:

4858.com 7

4858.com 8

进而找到rails项指标消除措施,安装rack-cors那些gem包

@TargetApi() 只屏蔽某一新api中才能动用的章程报的android lint错误

写在结尾

今天我们制作了2个简练符合webapi版本号更新迭代的ControllerSelector,可是还不是很圆满,因为许多都以hard
code,前面笔者会做二个支撑配置的ControllerSelector放到github上。

后面平昔在切磋eShopOnContrainers,近日也在商讨,可是工作的确有点忙,见谅见谅,假若我们.Net有哪些难点要么喜欢技术交友的,都能够加QQ群:376248054

具体方法如下:

举个例证,某些方法中利用了api9新加入的艺术,而项目设置的android:minSdkVersion=8,此时在艺术上加@SuppressLint(“NewApi”)

Gemfile中加入

和@TargetApi(Build.VERSION_CODES.GINGERBREAD)都可以,以上是通用的景况。

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

而当您在此形式中又引述了一个api11才到场的措施时,@TargetApi(Build.VE劲客SION_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地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有