【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 ```