客户端两种调用方式

SPI支持两种调用方式:Spring自动注入REST请求

对于以下SPI:

@FeignClient(“xxx-server”)
public interface XXXSpi{
    @LoginNeedless
    @RequestMapping(value="/v1/bizcircles",
                    method=RequestMethod.GET,params="districtId")
  List<Bizcircle>findByDistrictIdV1(@RequestParam("districtId")int districtId);
}

客户端既可以依赖:xxx-spi-1.0.0.jar,然后当做普通Spring Bean注入:

  public class ClientXXService{
     @Autowired
     private XXXSpi xxxSpi;

     public void doStufff(){
       //some logic
       List<District> districts= xxxSpi.findByDistrictIdV1(20000);
       // some logic
     }
  }

也可以使用任何HttpClient发起Http请求:

 GET http://api.route.dooioo.org/xxx/server/v1/bizcircles?districtId=20000

或者Web页面ajax请求(访问API网关):

$.get(“http://api.route.dooioo.org/xxx/server/v1/bizcircles?
        districtId=”+200000,function(data){
        console.log(data);
});

众所周知,Ajax请求必然会涉及跨域,我们的API网关已解决了此问题。

服务划分三个角色

下图演示了微服务的开发流程: 产品 - 拆分服务 - 服务实现 - 客户端/Web UI

微服务开发流程

具体到某个服务,则划分为三个角色:

  • Service SPI 服务声明
  • Service Server 服务提供者
  • Client/UI 服务调用方,包括FeignClient、Ajax、HttpClient。

三个概念

@LoginNeedless

SPI接口默认限制是用户登录后才能调用,手动添加@LoginNeedless以表明此接口可公开访问,无须校验用户是否登录。

假设我们有如下SPI:

@FeignClient("loupan-server")
public interface CitySpi{
    @RequestMapping(value="/v1/citys",method=RequestMethod.GET)
    List<City> findAllV1();
  }

如果通过API网关访问:

  GET http://api.route.dooioo.org/loupan/server/v1/citys

SPI提供方将直接响应401,因为此接口必须是登陆用户请求的。

正确的请求流程如下:

1,客户端首先向API网关申请登陆Token:

 POST http://api.route.dooioo.org/v1/client/token?userCode=87812
             &password=md5(s0x032.3)&credential=md5&companyId=1

如果工号和密码正确,响应数据如下:

    {
      "userCode": 87812,
       "companyId": 1,
       "token": "1032ace-300234b-2aedf45-32dcef"
    }

2,客户端添加自定义Request Header: X-Token,发送实际请求。

GET http://api.route.dooioo.org/loupan/server/v1/citys  
X-Token: 1032ace-300234b-2aedf45-32dcef

3,API网关根据X-Token查找登陆用户,将用户信息放在Request Header里,转发请求给后端节点:

  GET http://loupan-server-node:port/v1/citys
   X-Login-CompanyId: 1
   X-Login-UserCode: 87812
   X-Login-Token: 1032ace-300234b-2aedf45-32dcef

4,后端节点检查X-Login-CompanyIdX-Login-UserCodeX-Login-Token是否合法,不合法则直接响应401,否则正常响应。 如果接口业务需要登陆用户的工号或公司ID,则方法声明时,可添加需要的参数。

@FeignClient("loupan-server")
public interface CitySpi{
    @RequestMapping(value="/v1/citys",method=RequestMethod.GET)
    List<City> findAllV1(
    @RequestHeader(StandardHttpHeaders.X_Login_UserCode)int loginUserCode);
  }

@FeignClient("loupan-server")
public interface CitySpi{
  @RequestMapping(value="/v1/citys",method=RequestMethod.GET)
   List<City>  findAllV1(
   @RequestHeader(StandardHttpHeaders.X_Login_UserCode)int loginUserCode,
   @RequestHeader(StandardHttpHeaders.X_Login_CompanyId)int loginCompanyId);
  }

如果你的接口不涉及敏感业务数据,允许公开访问,则可以手动添加@LoginNeedless,表明此接口无需登陆,无需申请X-Token,客户端可直接访问。

 @FeignClient("loupan-server")
public interface CitySpi{
    @LoginNeedless
    @RequestMapping(value="/v1/citys",method=RequestMethod.GET)
    List<City> findAllV1();
  }

注意:如果通过Spring Autowired的方式调用SPI,目前不进行任何登陆校验,默认是信任的。

@LorikRest

上文提到,我们SPI有两种调用方式:Spring自动注入REST请求

 @FeignClient("loupan-server")
public interface CitySpi{
    @RequestMapping(value="/v1/citys/{id}",method=RequestMethod.GET)
    City findByIdV1(@PathVariable(value="id")int id);
  }

如果findByIdV1返回null,那么对于普通的JAVA调用来说就是记录不存在的意思,但是,对于REST请求来说,404才符合这个语义。

LorikRest注解是为了让SPI接口兼容REST访问而存在的。它提供了一些特性, 目前支持: Feature.NullTo404(如果方法返回null,则统一响应404),可以指定方法的业务码。

@FeignClient("loupan-server")
public interface CitySpi{
   @LorikRest(value={Feature.NullTo404},codes={21000})
   @RequestMapping(value="/v1/city/{id}",method=RequestMethod.GET)
   City findByIdV1(@PathVariable(value="id")int id);
  }

如果你的SPI暂无客户端REST访问,也可以不添加此标注。

@summary

@summary 是我们约定的Java Doc Tag,用于方法或类注释中,是功能简介,并不是代码的一部分。
@summary 最好20字以内,以简要概括类或方法的功能,便于API网关生成文档。

/**
  * 城市标准服务,目前仅支持上海、苏州。
  * @summary 城市
  * @Copyright (c) 2016, Lianjia Group All Rights Reserved.
  */
@FeignClient("loupan-server")
public interface CitySpi{
   /**
   * 中国大陆的每个城市都有一个国标码(GB/T 2260-2002),比如北京:110000,上海
   *  310000,推荐外键使用国标码来标识一个城市,而不要使用City#getId。
   * @author huisman
   * @version v1
   * @param gbCode 国标码
   * @return 城市
   * @since 2016-01-01
   * @summary 根据国标码查询城市
   */
   @LorikRest(value={Feature.NullTo404},codes={21000})
   @RequestMapping(value="/v1/city/{gbCode}",method=RequestMethod.GET)
   City findByGbCodeV1(@PathVariable(value="gbCode")int gbCode);
  }
© RD@上海链家 all right reserved,powered by Gitbook文件修订时间: 2016-11-01 01:48

results matching ""

    No results matching ""