zull网关搭建
zull: 统一请求路径,将请求分发给相应的微服务中 。请求直接发送到zull就行,不用关注每个微服务的端口号
zull搭建(开发工具使用的是idea)
- 新建module添加依赖(这里的父工程仅是一个springboot工程)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tensquare_parent</artifactId>
<groupId>com.tensquare</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>tensquare_manager</artifactId>
<dependencies>
//eureka客户端依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
//zull网关依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>com.tensquare</groupId>
<artifactId>tensquare_commen</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
- 添加配置application.yml(此步骤注意缩进)
server:
port: 9011
spring:
application:
name: tensquare-manager #指定服务名
eureka:
client:
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: http://127.0.0.1:6868/eureka/
instance:
prefer-ip-address: true
zuul:
routes:
tensquare-base: # 项目名称,自由填写
path: /base/** #配置请求URL的请求规则
serviceId: tensquare-base #指定Eureka注册中心中的服务id
tensquare-qa: # 项目名称,自由填写
path: /qa/** #配置请求URL的请求规则
serviceId: tensquare-qa #指定Eureka注册中心中的服务id
tensquare-friend: # 项目名称,自由填写
path: /friend/** #配置请求URL的请求规则
serviceId: tensquare-friend #指定Eureka注册中心中的服务id
tensquare-user: # 项目名称,自由填写
path: /user/** #配置请求URL的请求规则
serviceId: tensquare-user #指定Eureka注册中心中的服务id
//将zull敏感请求头设置为空,否则可能出现请求参数不能传递给微服务
sensitiveHeaders=
jwt:
config:
key: itcast # 密钥(加盐)
- 添加启动类
@SpringBootApplication
@EnableZuulProxy
//注意不要写成@EnableZuulServer
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class);
}
}
- 启动 eureka服务注册微服务,再启动zull网关
- 报错解决:
连接server失败或找不到server
首先确认eureka启动是否成功,不成功排查rureka的配置文件一定要配置registerWithEureka、 fetchRegistry为false正确配置如下
server:
port: 6868 #服务端口
eureka:
client:
registerWithEureka: false #是否将自己注册到Eureka服务中,本身就是所有无需注册
fetchRegistry: false #是否从Eureka中获取注册信息
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: http://127.0.0.1:${server.port}/eureka/
其次确认网关的配置文件缩进是否正确,缩进不正确导致层级关系错误,也会导致不能连接server
zull请求头转发不能获取问题
为什么存在zull转发请求头问题?
因为zull复制请求,发送给微服务。但是zull只复制标准请求头,不复制自定义的请求头传递token用的自定义"Authorization"头,因此要手动将非标准头转发给后端微服务。
例子
zull拦截请求并验证token
//获取原生request
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
if(request.getMethod().equals("OPTIONS")){
//直接放行OPTIONS方式的请求,供网关使用
return null;
}
//提取请求地址
String url=request.getRequestURL().toString();
if(url.indexOf("/admin/login")>0||url.indexOf("/admin/register")>0){ //判断如果是登录页面=>直接放行,不需要校验管理员权限
System.out.println("登陆页面"+url);
return null;
}
String authHeader =(String)request.getHeader("Authorization");//获取头信息
//判断是否存在
if (authHeader!=null&&authHeader.startsWith("Bearer ")){
String token = authHeader.substring(7);
Claims claims = jwtUtil.parse(token); //解析token
if (claims!=null){
if ("admin".equals(claims.get("role"))){//=>是管理员,转发到微服务中,并携带Authorization头
currentContext.addZuulRequestHeader("Authorization",authHeader);
return null;
}
}
}
//当前用户未登录,或角色不是管理员 => 阻止网关转发
currentContext.setSendZuulResponse(false);//终止运行
currentContext.setResponseStatusCode(401);//指定返回响应的状态码
//为响应添加ContentType头
currentContext.getResponse().setContentType("text/html;charset=UTF‐8");
currentContext.setResponseBody("no privilege!"); //指定响应内容
return null;
微服务获取请求头
String authorization = request.getHeader("Authorization");
if (authorization!=null&&!"".equals(authorization)&&authorization.startsWith("Bearer ")){
//解析token
String token = authorization.substring(7);
Claims claims = jwtUtil.parse(token);
if (claims==null){
return false;
}
String role = (String)claims.get("role");
if ("admin".equals(role)){
request.setAttribute("admin_role",role);
System.out.println("jwt载荷放入admin_role");
}
if ("user".equals(role)){
request.setAttribute("user_role",role);
System.out.println("jwt载荷放入user_role");
}
return true;
}
System.out.println("拦截器拦截"+request.getAttribute("admin_role"));
//执行操作
return false;
错误解决:
后端微服务接收到的"Authorization"请求头为null
if ("admin".equals(claims.get("role"))){//=>是管理员,转发到微服务中,并携带Authorization头
currentContext.addZuulRequestHeader("Authorization",authHeader);
return null;
}
确认zull已经将token放入到"Authorization"。
原因: Authorization是敏感头,zull并不会转发这个请求头
解决:
- 不要使用敏感字段,改成"Authorization1"就可以
- 在配置文件中配置zull的敏感字段为空
sensitiveHeaders=