【Spring Cloud 04】Zuul网关
2021-02-26 09:35:15
创建一个gateway的Module
pom
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
```
application.yml
```yaml
server:
port: 8000
spring:
application:
name: gateway
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://your-eureka-ip:8761/eureka/
instance:
prefer-ip-address: true
```
启动类
```java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class,args);
}
}
```
application.yml中,提定url也服务之间的映射关系
```yaml
zuul:
ignored-services: "*" # 关闭自动映射
routes:
foo:
path: /foo/**
strip-prefix: true # 默认为true,表示服务中的url没有这个前缀,需要去掉之后调用服务
service-id: foo-service
bar:
path: /bar/**
service-id: bar-service
```
通过网关访问微服务:
http://your-gateway-ip:8000/foo/xxx
http://your-gateway-ip:8000/bar/xxx
过滤器
```java
package com.example.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
@Component
public class TokenFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletResponse response = requestContext.getResponse();
// 从请求头中获取token
String token = requestContext.getRequest().getHeader("token");
if (token == null) {
Map<String, String> map = new HashMap<>();
map.put("code", "ERROR");
map.put("message", "INVALID_TOKEN");
map.put("data", null);
stop(requestContext, map); // 停止
return null;
}
// todo 通过token获取当前用户信息
String userId = "1";
requestContext.addZuulRequestHeader("current-user-id", userId);
return null;
}
private void stop(RequestContext requestContext, Map map) {
// 对其它过滤器都不会被执行了,直到 SendResponseFilter,输出Response的内容
requestContext.setSendZuulResponse(false);
HttpServletResponse response = requestContext.getResponse();
response.setHeader("content-type", "application/json;charset=UTF-8");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
requestContext.setResponseStatusCode(200);
requestContext.setResponseBody(objToStr(map));
}
public static <T> String objToStr(T obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
```
在微服务中,直接在Http请求头中获取当前用户ID,例如 foo-svc中添加一个控制器
```java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
public class DemoController {
@GetMapping("/demo/test")
public String test(HttpServletRequest request) {
String userId = request.getHeader("current-user-id");
return userId;
}
}
```
你可以用以下两种方式访问
```
# 直接访问foo-svc的端口8001访问
http://your-foo-svc-ip:8001/demo/test
# 通过网关访问(需要加上前缀)
http://your-gateway-ip:8000/foo/demo/test
```