Http服务化改造实践

简介: Http服务化改造实践

在微服务架构体系中远程RPC调用主要包括Dubbo与Http调用两个大类,由于Dubbo拥有服务注册中心,并且起服务的命名非常规范,使用包名.类名.方法名进行描述。


而http调用通常都是使用httpclient等相关类库,这些在使用上并没有问题,但API都是分散在整个工程的各个地方,如果HTTP调用也可以使用类似Dubbo服务的表示方法,采用声明式定义就好了。


在开源的世界中只有想不到,没有找不到,为了解决Feign的声明式服务化管理,Feign框架应运而生,本文主要介绍如何使用Feign实现Http服务声明化管理与调用。


1、什么是Feign


Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求。


Feign通过注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,封装了http调用流程。


2、快速入门实例


2.1定义客户端


首先要引入Feign的maven依赖,如下图所示:

<dependency>
   <groupId>com.netflix.feign</groupId>
   <artifactId>feign-core</artifactId>
   <version>8.18.0</version>
 </dependency>


2.2 定义服务调用API(类似Dubbo API)


服务调用的API声明代码如下所示:

@FeignClient
public interface HelloControllerApi {
 @RequestLine("GET /api/hello?name={name}")
 String hello(@Param(value = "name") String name);
}

这里的要点是使用@FeignClient进行声明。声明后就可以通过HelloControllerApi进行远程HTTP调用,示例代码如下:

public class HelloControllerApiTest {
 private HelloControllerApi service;
 @Before
 public void before(){
  service = Feign.builder()
    .options(new Request.Options(1000, 3500))
    .retryer(new Retryer.Default(5000, 5000, 3))
    .target(HelloControllerApi.class, "http://127.0.0.1:8080");
 }
 @Test
 public void hello(){
        // 调用http://127.0.0.1:8080/api/hello?name=world 的http接口
  System.out.println(service.hello("world"));
 }
}

当然需要在调用方的启动类上增加@EnableFeignClients(defaultConfiguration = FeignConfiguration.class)注解。


2.3定义服务端


服务端与Feign并无关系,主要按照API的方式实现即可,服务端实现代码如下所示:

@Controller
@RequestMapping(value = "api")
public class HelloController {
 @RequestMapping(value = "/hello", method = {RequestMethod.GET})
 @ResponseBody
 public String list(@RequestParam String name) {
  return "Hello " + name;
 }
}
//启动类
@SpringBootApplication(scanBasePackages = {"com.vhicool.manager"})
public class ManagerApplication {
 public static void main(String[] args) {
  SpringApplication.run(ManagerApplication.class, args);
 }
}


3、实现签名校验


上述只是简单实用Feign,接下来以实现签名校验为例展示Feign的扩展机制。


签名验证是最常见的安全机制,首先在客户端定义一个签名拦截器,用于生成签名信息,示范代码如下图所示:

public class AuthRequestInterceptor implements feign.RequestInterceptor {
 private TokenService tokenService;
 public AuthRequestInterceptor(TokenService tokenService) {
  this.tokenService = tokenService;
 }
 @Override
 public void apply(RequestTemplate template) {
  template.header("token", tokenService.getToken());
 }
}

并且在Feign的全局配置文件中创建对应的拦截器,示例代码如下:

public class FeignConfiguration {
  @Bean
 public RequestInterceptor authRequestInterceptor(ResourceIdentity resourceIdentity) {
  AuthRequestInterceptor authRequestInterceptor = new AuthRequestInterceptor(resourceIdentity);
  authRequestInterceptor.setErrorEncodeType(errorEncodeType);
  return authRequestInterceptor;
 }
}

同时在服务端获取token并对token进行校验,示例代码如下:

@Component
public class AuthFilter implements Filter {
 @Autowired
 private TokenService tokeService;
 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  String remoteToken = ((HttpServletRequest) servletRequest).getHeader("token");
  if(!tokeService.valid(token)) {
      //异常处理逻辑
      return;
    }
  filterChain.doFilter(servletRequest, servletResponse);
 }
}


4、服务端自动生成Feign


上面的示例虽然实现了服务接口的声明式管理,但调用端、客户端并没有显示的约束关系,接下来展示如何使用客户端、服务端使用继承方式定义服务调用API。


例如要实现如下图的效果:

92d8beefe2506424f36d677979170b7a.jpg

原生的Feign无法实现该效果,我们需要使用OpenFeign类库,两者之间的对比如下图所示:

0f326895841c7c7ca3b957e76d124cbf.jpg

接下来详细介绍具体实现方法。


4.1 提取公共API


首先使用一个模块定义公共API,需要引入maven依赖,代码示例如下所示:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

接下来定义公共的服务接口,客户端、服务端都需要实现该接口,公共服务端接口定义如下:

public interface IUserController {
 @RequestMapping(value = "user/list-all", method = {RequestMethod.GET})
 List<String> listAll(@RequestParam String name);
}


4.2 服务端实现公共API


首先需要添加相应的maven依赖,代码如下:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vhicool</groupId>
            <artifactId>feign-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

服务端采用继承方式实现,具体代码如下所示:

@Controller
@RequestMapping
public class UserController implements IUserController {
 @Override
 @ResponseBody
 public List<String> listAll(String name) {
  ArrayList<String> list = new ArrayList<>();
  list.add("达菲");
  list.add("olu");
  list.add(name);
  return list;
 }
}


4.3 客户端实现公共API


客户端首先同样需要增加相应的依赖,具体代码如下所示:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.1.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
         <dependency>
            <groupId>com.vhicool</groupId>
            <artifactId>feign-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

客户端服务调用类需要继承公共API:

@FeignClient(value = "user", url = "http://localhost:8080")
public interface UserApi extends IUserController {
}

同时客户端启动类需要增加@EnableFeignClients注解,具体示例代码如下所示:

@SpringBootApplication
@EnableFeignClients
public class ManagerApplication {
 public static void main(String[] args) {
  SpringApplication.run(ManagerApplication.class, args);
 }
}

同样基于Springboot编程方式,可以为Feign配置全局参数,具体如下:

@Configuration
public class FeignConfiguration {
 /**
  * 请求超时时间
  * @return
  */
 @Bean
 public Request.Options options() {
  return new Request.Options(2000, 3500);
 }
  //拦截器等定义
}

接下来客户端就可以用如下方式进行调用:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {
 @Autowired
 private UserApi userApi;
 @Test
 public void listAll() {
  System.out.println(userApi.listAll("饼饼"));
 }
}

时,当前项目编译的jar包,类也已经被替换成我们自定义的类,目标达成。

相关文章
|
7月前
|
算法 API UED
基于Gin框架的HTTP接口限速实践
基于Gin框架的HTTP接口限速实践
169 0
|
2月前
|
Rust 前端开发 API
Tauri 开发实践 — Tauri HTTP 请求开发
本文介绍了如何在 Tauri 中发起 HTTP 请求。首先通过安装 Tauri 生态中的工具包并配置 `tauri.conf.json` 文件来允许特定域名的 HTTP 通信。接着封装了一个简单的 HTTP 客户端类,并在页面中使用该客户端实现 GET 和 POST 请求。最后提供了完整的源码地址以供参考。此功能使得桌面应用能够与远程服务器进行交互,增强了应用的实用性。
152 1
Tauri 开发实践 — Tauri HTTP 请求开发
|
2月前
|
存储 缓存 NoSQL
保持HTTP会话状态:缓存策略与实践
保持HTTP会话状态:缓存策略与实践
|
2月前
|
存储 JSON API
HTTP 请求与响应处理:C#中的实践
【10月更文挑战第4天】在现代Web开发中,HTTP协议至关重要,无论构建Web应用还是API开发,都需要熟练掌握HTTP请求与响应处理。本文从C#角度出发,介绍HTTP基础知识,包括请求与响应结构,并通过`HttpClient`库演示如何发送GET请求及处理响应,同时分析常见错误并提供解决方案,助你更高效地完成HTTP相关任务。
108 2
|
2月前
|
存储 缓存 监控
HTTP:强缓存优化实践
HTTP强缓存是提升网站性能的关键技术之一。通过精心设计缓存策略,不仅可以显著减少网络延迟,还能降低服务器负载,提升用户体验。实施上述最佳实践,结合持续的监控与调整,能够确保缓存机制高效且稳定地服务于网站性能优化目标。
56 3
|
6月前
|
程序员 API 开发者
Socket与HTTP协议的实践
【6月更文挑战第4天】本文介绍了Python中的网络编程,包括Socket编程和基于HTTP协议的实践。Socket编程是网络通信的基础,Python的`socket`模块简化了其使用。文中展示了服务器和客户端的简单示例,以及如何通过多线程处理多个客户端连接。另外,文章讨论了HTTP协议,推荐了`requests`库,并给出了发送GET和POST请求的例子。最后,总结了Socket编程和HTTP协议在网络编程中的应用及其在Web开发和API交互中的重要性。
70 5
|
7月前
|
前端开发 API UED
AngularJS的$http服务:深入解析与进行HTTP请求的技术实践
【4月更文挑战第28天】AngularJS的$http服务是核心组件,用于发起HTTP请求与服务器通信。$http服务简化了通信过程,通过深入理解和实践,能构建高效、可靠的前端应用。
|
7月前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。
150 0
|
7月前
|
数据采集 缓存 监控
HTTP与URL基础解析及简单示例实践
HTTP与URL基础解析及简单示例实践
|
7月前
|
存储 缓存 网络协议
淘宝HTTP3/QUIC技术演进与实践
淘宝HTTP3/QUIC技术演进与实践
348 0
淘宝HTTP3/QUIC技术演进与实践
下一篇
DataWorks