swagger原理分析与运用进程中相见的坑,中http请求爆发access

在api项目中 本地品种无法访问服务器api

swagger原理分析与运用进程中相见的坑,中http请求爆发access。在Android代码中,大家有时会利用比大家在AndroidManifest中设置的android:minSdkVersion版本更高的法子,此时编写翻译器会提醒警示,

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

swagger简介

swagger确实是个好东西,能够跟据业务代码自动生成相关的api接口文书档案,越发用于restful风格中的项目,开发职员大致能够不用尤其去维护rest
api,这些框架能够活动为你的政工代码生成restfut风格的api,而且还提供对应的测试界面,自动展现json格式的响应。大大方便了后台开发人士与前者的牵连与联调费用。

springfox-swagger简介

签于swagger的无敌功用,java开源界大拿spring框架快捷跟上,它充足利用自已的优势,把swagger集成到本人的品种里,整了二个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 {}

在意到,上边是3个空的java类文件,类名能够随便钦命,但无法不进入上述类中标注的@Configuration、@EnableWebMvc、@EnableSwagger2多个评释,那样就到位了springmvc与springfox的基本集成,有了八个评释,项目运行后就足以从来用类似于以下的地点来查阅api列表了:

那着实是二个很神奇的功能,简单的四个注明,系统就活动展现出档次里存有Controller类的具有api了。以往,我们就那几个布局类动手,简单分析它的原理。那些类中从不别的代码,很鲜明,八个表明起了首要的效应。当中@Configuration注脚是spring框架中笔者就一些,它是一个被@Component元注明标识的注释,所以有了那些表明后,spring会自动把这些类实例化成3个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,

第3个ApiListingBuilderPlugin,它有多个落到实处类,分别是ApiListingReader和SwaggerApiListingReader。在那之中ApiListing里德r会自动跟据Controller类型生成api列表,而SwaggerApiListing里德r会跟据有@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,它是三个一直不落实别的接口的bean,但它里面有好多PluginRegistry类型的习性,而且都是通过@Autowired评释把属性值注入进来的。接合它的类名来看,很不难想到,那一个正是管理全部plug的一个管理器了。很好精通,因为ComponentScan注脚的布署,全体的plug实例都会被spring实例化成二个bean,然后被注入到那个DocumentationPluginsManager实例中被统一保管起来。在那一个package中的另一个首要的类DocumentationPluginsBootstrapper,看名字就足以猜到,他只怕正是plug的开行类了。点进去看具体时就足以窥见,他果然是3个被@Component标识了的组件,而且它的构造方法中注入了正要描述的DocumentationPluginsManager实例,而且最重点的,它还实现了斯马特Lifecycle接口。对spring
bean生命周期有所了然的人的都知晓,这些组件在被实例化为3个bean纳入srping
context中被管理起来的时候,会活动调用它的start()方法。点到start()中看代码时就会意识,它有一行代码scanDocumentation(buildContext(each));正是用来扫描api文书档案的。进一步跟踪那几个点子的代码,就足以窥见,那一个主意最后会通过它的DocumentationPluginsManager属性把拥有plug调起一起扫描整个种类并生成api文书档案。扫描的结果,缓存在DocumentationCache那个类的2个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第3大坑:配置类生成的bean必须与spring
mvc共用同二个上下文。

前文描述了,在springmvc项目中,集成springfox是固然在项目写三个之类的尚未任何事情代码的简便安排类就足以了。

@Configuration
@EnableWebMvc
@EnableSwagger2
publicclass ApiConfig {
}

因为@Configuration证明的成效,spring会自动把它实例化成1个bean注入到上下文。但切记要小心的二个坑就是:那么些bean所在的上下文必须跟spring
mvc为同3个上下文。怎么解理呢?因为在事实上的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代码重新编写翻译。基于此,小编推荐的2个方法,通过spring最守旧的xml文件配置格局。具体做法正是去掉@Configuration评释,然后它写3个像样于<bean
class=”com.jad.web.mvc.swagger.conf.ApiConfig”/>那样的bean配置到spring的xml配置文件中。在root
context与mvc的context分开的档次中,直接配备到spring-mvc.xml中,那样就保障了它跟springmvc
的context一定处于同2个context中。

springfox第③大坑:Controller类的参数,注意防止出现无限递归的场所。

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

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

那是多数程序员喜欢在Controller中写的改动有些实体的代码。在跟swagger集成的时候,那里有三个大坑。要是MenuVo这么些类中具有的质量都是着力类型,那辛亏,不会出怎么着难题。但假诺这些类里面有局地别的的自定义类型的性情,而且这特特性又直白或直接的留存它自个儿类型的质量,那就会出题目。例如:假若MenuVo那个类是菜单类,在这一个类时又包含MenuVo类型的二个属性parent代表它的父级菜单。那样的话,系统运营时swagger模块就因不能够加载这么些api而一直报错。报错的由来正是,在加载那几个主意的长河中会解析那些update方法的参数,发现参数MenuVo不是简单类型,则会活动以递归的方法诠释它兼具的类属性。那样就很不难陷于万分递归的死循环。

为了化解这么些标题,作者当下只是本身写了二个OperationParameterReader插件达成类以及它依靠的ModelAttributeParameterExpander工具类,通过安排的办法替换掉到srpingfox原来的这五个类,偷梁换柱般的把参数解析那个逻辑替换掉,并避让无限递归。当然,这一定于是一种修改源码级其余章程。小编眼下还没有找到化解那几个难点的更完美的措施,所以,只好建议大家在用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分为了两组。在那种状态下,必须给每一组钦命2个例外的名称,比如上边代码中的”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。

澳门葡京备用网址 1

缓解方法是在点子上足够@SuppressLint(“NewApi”)大概@TargetApi()。

问题

    以Asp.Net Web Api 为例,随着工作的壮大,产品的迭代,大家的web
api也在跟着变动,很多时候会并发四个本子共存的场景,那一个时候大家就须要规划二个支撑版本号的web
api link,比如:

原先:

如今:

在大家刚设计的时候,有可能没有考虑版本的标题,笔者看到许多的档次都会在link后进入贰个“?version=”的法子,那种措施真正能够化解难题,但对Asp.Net
Web
Api来说,进入的要么同1个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加入到一个字典中

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

澳门葡京备用网址 4

澳门葡京备用网址 5

澳门葡京备用网址 6

@SuppressLint(“NewApi”)屏蔽一切新api中才能选拔的点子报的android
lint错误

制作属于本身的Selector

思路有了,那改造起来也相当不难,后天大家先做3个简约的,等有时光改成可布署的。

先是步,大家先成立二个Selector类,继承自DefaultHttpControllerSelector,然后开端化的时候成立2个属于我们友好的字典:

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群: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  
            //  
}  

 

相关文章

发表评论

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

*
*
Website