Mình đã giới thiệu với các bạn cách xây dựng một API Gateway sử dụng Zuul Proxy của Spring Cloud Netflix. Trong bài viết này, mình giới thiệu với các bạn một cách khác, sử dụng một thư viện khác trong hệ sinh thái Spring framework, đó là Spring Cloud Gateway các bạn nhé!
Nói nôm na về nguyên tắc hoạt động của một API Gateway thì nó sẽ cho phép chúng ta có thể cấu hình để khi một request tới nó thì đối với request này, nó sẽ forward request tới service này, còn request kia nó sẽ forward cho service kia. Spring Cloud Gateway cũng có chức năng như vậy. Spring Cloud Gateway hỗ trợ chúng ta các filter, giúp chúng ta có thể thay đổi một request bất kỳ tới các service bên trong như thêm request parameter, thay đổi request URL, thêm header này nọ, … Chúng ta có thể thêm mới các custom filter, nghĩa là các bạn có thể viết code Java, để thêm bất kỳ các logic xử lý khác trước khi một request thực sự được forward đến target service.
Để làm ví dụ cho bài viết này, để đơn giản cho các bạn có một cái nhìn overview về cách Spring Cloud Gateway làm việc, mình sẽ tạo mới một ứng dụng sử dụng Spring Cloud Gateway đóng vai trò là API Gateway và hai project service khác là Student Service và Class Service đóng vai trò là services mà chúng ta cần gọi tới. Tuỳ theo request của người dùng mà ứng dụng Gateway này sẽ forward request tới service tương ứng.
High level architecture của ứng dụng này như sau:
Project của ứng dụng có nội dung như sau:
Bây giờ, mình sẽ implement cho 2 service Student Service và Class Service 2 API đơn giản, trả về 2 dòng chữ đơn giản. Khi người dùng request tới ứng dụng Gateway, tuỳ theo request, người dùng sẽ nhận response tương ứng các bạn nhé!
Student Service
Service này là một Spring Boot application. API đơn giản mà mình sẽ expose cho service này sẽ như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.huongdanjava.springcloud.gateway.introduction.studentservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class StudentServiceApplication { public static void main(String[] args) { SpringApplication.run(StudentServiceApplication.class, args); } @GetMapping("/students/hello") public String hello() { return "Hello from Student Service"; } } |
Như các bạn thấy, mình chỉ expose endpoint “/students/hello” với response là dòng chữ “Hello from Student Service”.
Service này sẽ chạy ở port 8081 các bạn nhé:
1 2 |
server: port: 8081 |
Class Service
Tương tự như Student Service, Class Service cũng là một Spring Boot application và nó cũng expose một endpoint đơn giản như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.huongdanjava.springcloud.gateway.introduction.classservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class ClassServiceApplication { public static void main(String[] args) { SpringApplication.run(ClassServiceApplication.class, args); } @GetMapping("/classes/hello") public String hello() { return "Hello from Class Service"; } } |
Service này sẽ chạy ở port 8082 các bạn nhé:
1 2 |
server: port: 8082 |
API Gateway
Ứng dụng API Gateway cũng sẽ là một Spring Boot project với Spring Cloud Gateway dependency để làm API Gateway.
Để cấu hình các service trong Spring Cloud Gateway, chúng ta có 2 cách:
- Sử dụng các properties
- Hoặc sử dụng code Java được cung cấp bởi Spring Cloud Gateway.
Trong bài viết này, mình sẽ hướng dẫn các bạn sử dụng các properties các bạn nhé!
Chúng ta sẽ sử dụng một bộ với ít nhất các properties sau để cấu hình cho một service:
1 2 3 4 5 6 7 8 9 10 |
spring: cloud: gateway: server: webmvc: routes: - id: <service_name> uri: <service_uri> predicates: - Path=<context_path> |
Trong đó:
- service_name là tên của service
- service_uri là thông tn host, port của service
- predicates là danh sách các request mà API Gateway sẽ catch up và forward request từ người dùng đến service đó.
Các bạn có thể định nghĩa nhiều service, tương ứng với mỗi service là một phần tử trong routes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
spring: cloud: gateway: server: webmvc: routes: - id: <service1_name> uri: <service1_uri> predicates: - Path=<context_path> - id: <service2_name> uri: <service2_uri> predicates: - Path=<context_path> |
Trong ví dụ của mình, các bạn có thể cấu hình thông tin các service trên trong API Gateway như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
spring: cloud: gateway: server: webmvc: routes: - id: studentService uri: http://localhost:8081 predicates: - Path=/students/** - id: classService uri: http://localhost:8082 predicates: - Path=/classes/** |
Với khai báo trên, các request tới ứng dụng Gateway có endpoint bắt đầu là /students sẽ được forward tới Student Service, còn những request nào có endpoint bắt đầu là /classes sẽ được forward tới Class Service đó các bạn!
Ứng dụng Gateway của mình sẽ chạy ở port mặc định 8080 nên bây giờ nếu các bạn chạy ứng dụng API Gateway và 2 service trên, sau đó request tới API Gateway với request http://localhost:8080/classes/hello, các bạn sẽ thấy kết quả như sau:
Còn nếu các bạn request tới địa chỉ http://localhost:8080/students/hello, các bạn sẽ thấy response từ Student Service như sau:
Như vậy là chúng ta đã xây dựng thành công một ứng dụng API Gateway đơn giản có thể handle request và forward request tới backend service tương ứng rồi đó các bạn!