基于Servlet体系的HTTP请求代理转发Spring Boot组件 (2)

ServiceRoute对象主要包含下游转发服务的HTTP地址、端口号、固定Header信息

public class ServiceRoute { /** * 转发模式 */ private RouteModeEnum mode; /** * 匹配值 */ private String value; /** * 转发目标地址,例如::8999 */ private String uri; /** * 发送请求头 */ private Map<String,String> headers; //getter and setter }

而ServiceRoute是最终交给开发者配置的信息,转发请求方式,判断逻辑如下:

/** * 校验当前路由规则是否符合 * @param serviceRoute 路由实例 * @param servletRequest 请求对象 * @return 是否符合规则 */ protected boolean checkRoute(ServiceRoute serviceRoute,HttpServletRequest servletRequest){ boolean flag=false; if (serviceRoute!=null){ switch (serviceRoute.getMode()){ //基于请求头 case ROUTE_MODE_HEADER: String value=servletRequest.getHeader(ROUTE_MODE_HEADER_NAME); flag=StrUtil.equalsIgnoreCase(value,serviceRoute.getValue()); break; //基于URI的前缀匹配 case ROUTE_MODE_PREFIX: flag=servletRequest.getRequestURI().startsWith(serviceRoute.getValue()); break; //基于URI的后缀匹配 case ROUTE_MODE_SUFFIX: flag=servletRequest.getRequestURI().endsWith(serviceRoute.getValue()); break; } } return flag; }

针对权限的设计,在ServletGatewayRouteProxyFilter中,提供了ServletGatewayAuthentication接口,该接口设计如下:

public interface ServletGatewayAuthentication { /** * 权限校验 * @param request 请求request对象 * @param response 响应对象 * @return 是否权限校验通过 */ boolean auth(ServletRequest request, ServletResponse response); /** * 权限校验失败后的处理逻辑 * @param request 请求对象 * @param response 响应对象 */ void failedHandle(ServletRequest request, ServletResponse response); /** * 是否需要鉴权,默认true * @return 是否需要鉴权 */ default boolean required(){return true;} }

主要包含三个接口:

auth:权限验证,返回布尔值,该接口方法主要是兼容系统中的权限,对于当前的请求,可以方便的做出权限判断,交由开发者实现

failedHandle:如果权限验证失败,最终响应信息给前端,开发者实现

required:是否需要鉴权的标志,默认是true,代表需要鉴权

最后再来看代理请求的执行逻辑(RouteDispatcher.java#execute()方法),部分核心代码如下:

public void execute(HttpServletRequest request, HttpServletResponse response,ServiceRoute serviceRoute){ try{ //构建请求对象 RouteRequestContext routeContext=new RouteRequestContext(); //请求对象赋值 this.buildContext(routeContext,request,serviceRoute); //发送请求 RouteResponse routeResponse=routeExecutor.executor(routeContext); //响应结果 writeResponseHeader(routeResponse,response); writeBody(routeResponse,response); }catch (Exception e){ logger.error("has Error:{}",e.getMessage()); logger.error(e.getMessage(),e); //write Default writeDefault(request,response,e.getMessage()); } }

针对请求上下文的赋值,主要是接收当前请求的请求参数以及请求头,并且根据ServiceRoute路由基础信息,进行基础赋值,代码如下:

/** * 构建路由的请求上下文 * @param routeRequestContext 请求上下文对象 * @param request 请求 * @param serviceRoute 路由实例 * @throws IOException IO异常 */ protected void buildContext(RouteRequestContext routeRequestContext,HttpServletRequest request,ServiceRoute serviceRoute) throws IOException { //String uri="http://knife4j.xiaominfo.com"; String uri=serviceRoute.getUri(); if (StrUtil.isBlank(uri)){ throw new RuntimeException("Uri is Empty"); } String host=URI.create(uri).getHost(); String fromUri=request.getRequestURI(); StringBuilder requestUrlBuilder=new StringBuilder(); requestUrlBuilder.append(uri); //判断当前聚合项目的contextPath if (StrUtil.isNotBlank(this.rootPath)&&!StrUtil.equals(this.rootPath,ROUTE_BASE_PATH)){ fromUri=fromUri.replaceFirst(this.rootPath,""); } if (serviceRoute.getMode()== RouteModeEnum.ROUTE_MODE_PREFIX){ //前缀转发,替换 fromUri=fromUri.replaceFirst(serviceRoute.getValue(),"http://www.likecs.com/"); } if (!StrUtil.startWith(fromUri,"http://www.likecs.com/")){ requestUrlBuilder.append("http://www.likecs.com/"); } requestUrlBuilder.append(fromUri); //String requestUrl=uri+fromUri; String requestUrl=requestUrlBuilder.toString(); logger.info("目标请求Url:{},请求类型:{},Host:{}",requestUrl,request.getMethod(),host); routeRequestContext.setOriginalUri(fromUri); routeRequestContext.setUrl(requestUrl); routeRequestContext.setMethod(request.getMethod()); Enumeration<String> enumeration=request.getHeaderNames(); while (enumeration.hasMoreElements()){ String key=enumeration.nextElement(); String value=request.getHeader(key); if (!ignoreHeaders.contains(key.toLowerCase())){ routeRequestContext.addHeader(key,value); } } //是否有默认Header需要发送 if (CollectionUtil.isNotEmpty(serviceRoute.getHeaders())){ for (Map.Entry<String,String> entry:serviceRoute.getHeaders().entrySet()){ routeRequestContext.addHeader(entry.getKey(),entry.getValue()); } } routeRequestContext.addHeader("Host",host); Enumeration<String> params=request.getParameterNames(); while (params.hasMoreElements()){ String name=params.nextElement(); String value=request.getParameter(name); //logger.info("param-name:{},value:{}",name,value); routeRequestContext.addParam(name,value); } routeRequestContext.setRequestContent(request.getInputStream()); } 使用指南

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxyps.html