|
|
@@ -0,0 +1,508 @@
|
|
|
+package com.micro.cloud.gateway.filters;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.serializer.PascalNameFilter;
|
|
|
+import com.alibaba.fastjson.serializer.SerializerFeature;
|
|
|
+import com.google.common.net.HttpHeaders;
|
|
|
+import com.micro.cloud.core.constans.CommonMessage;
|
|
|
+import com.micro.cloud.core.constans.GatewayConstans;
|
|
|
+import com.micro.cloud.core.constans.GatewayMessage;
|
|
|
+import com.micro.cloud.core.http.response.Response;
|
|
|
+import com.micro.cloud.excetions.GatewayException;
|
|
|
+import com.micro.cloud.utils.HttpServletReqestUtil;
|
|
|
+import com.netflix.client.ClientException;
|
|
|
+import com.netflix.hystrix.exception.HystrixRuntimeException;
|
|
|
+import com.netflix.zuul.ZuulFilter;
|
|
|
+import com.netflix.zuul.context.RequestContext;
|
|
|
+import com.netflix.zuul.exception.ZuulException;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
|
|
+import org.springframework.cloud.netflix.ribbon.support.RibbonCommandContext;
|
|
|
+import org.springframework.cloud.netflix.ribbon.support.RibbonRequestCustomizer;
|
|
|
+import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
|
|
|
+import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand;
|
|
|
+import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
|
|
|
+import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
|
|
|
+import org.springframework.http.HttpStatus;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
+import org.springframework.http.client.ClientHttpResponse;
|
|
|
+import org.springframework.util.MultiValueMap;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 重写RibbonRoutingFilter的run()和buildCommondConext(),使其支持接口参数Commond模式
|
|
|
+ *
|
|
|
+ * @author zzt
|
|
|
+ *
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+public class RouteRequestFilter extends ZuulFilter {
|
|
|
+
|
|
|
+ private static final PascalNameFilter pascalFilter = new PascalNameFilter();
|
|
|
+
|
|
|
+ private ProxyRequestHelper helper;
|
|
|
+
|
|
|
+ private boolean useServlet31 = true;
|
|
|
+
|
|
|
+ private RibbonCommandFactory<?> ribbonCommandFactory;
|
|
|
+
|
|
|
+ @SuppressWarnings("rawtypes")
|
|
|
+ private List<RibbonRequestCustomizer> requestCustomizers;
|
|
|
+
|
|
|
+ private Map<String, String> service;
|
|
|
+
|
|
|
+// @Autowired
|
|
|
+// private RedisUtil redisUtil;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private IConfigRemoteService configService;
|
|
|
+
|
|
|
+ private int chooseRetryCount;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private LoadBalancerClient loadBalancer;
|
|
|
+
|
|
|
+ @SuppressWarnings("rawtypes")
|
|
|
+ public RouteRequestFilter(ProxyRequestHelper helper, RibbonCommandFactory<?> ribbonCommandFactory,
|
|
|
+ List<RibbonRequestCustomizer> requestCustomizers,
|
|
|
+ Map<String,String> service,
|
|
|
+ int chooseRetryCount) {
|
|
|
+ this.helper = helper;
|
|
|
+ this.ribbonCommandFactory = ribbonCommandFactory;
|
|
|
+ this.requestCustomizers = requestCustomizers;
|
|
|
+ this.service = service;
|
|
|
+ this.chooseRetryCount = chooseRetryCount;
|
|
|
+ try {
|
|
|
+ HttpServletResponse.class.getMethod("getContentLengthLong");
|
|
|
+ }catch (Exception e) {
|
|
|
+ useServlet31 = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean shouldFilter() {
|
|
|
+ RequestContext ctx = RequestContext.getCurrentContext();
|
|
|
+ return (ctx.getRouteHost() ==null
|
|
|
+ && ctx.get(FilterConstants.SERVICE_ID_KEY) != null
|
|
|
+ && ctx.sendZuulResponse()
|
|
|
+ && (Boolean)ctx.get(GatewayConstans.AuthTag)
|
|
|
+ && !(Boolean)ctx.get(GatewayConstans.RateLimitExpire)
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String filterType() {
|
|
|
+ return FilterConstants.ROUTE_TYPE;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int filterOrder() {
|
|
|
+ return FilterConstants.RIBBON_ROUTING_FILTER_ORDER;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object run() throws ZuulException {
|
|
|
+ log.debug(">>>>>>>>>>>>>>>>>>>>网关路由转发开始>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
|
|
|
+ log.debug(">>> 网关路由转发开始.");
|
|
|
+ RequestContext context = RequestContext.getCurrentContext();
|
|
|
+ this.helper.addIgnoredHeaders();
|
|
|
+ try {
|
|
|
+ HttpServletRequest request = context.getRequest();
|
|
|
+ String command = HttpServletReqestUtil.getParameter(request, GatewayConstans.API_COMMAND_ACTION);
|
|
|
+
|
|
|
+ String requestURI = request.getRequestURI();
|
|
|
+ RibbonCommandContext commandContext = null;
|
|
|
+ if(command!=null&&requestURI.startsWith(GatewayConstans.COMMAND_API)) {
|
|
|
+ commandContext = buildCommandContext(context,command);
|
|
|
+ }else {
|
|
|
+ commandContext = buildCommandContext(context,null);
|
|
|
+ }
|
|
|
+ ClientHttpResponse response = forward(commandContext);
|
|
|
+ setResponse(response);
|
|
|
+ log.debug(">>> 网关路由转发结束,响应消息给客户端");
|
|
|
+ return response;
|
|
|
+ }catch (Exception e) {
|
|
|
+ log.error(">>> 网关路由处理失败,异常【{}】",e.getMessage());
|
|
|
+ return buildExceptionResponse(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行转发
|
|
|
+ * @param context
|
|
|
+ * @return
|
|
|
+ * @throws GatewayException
|
|
|
+ */
|
|
|
+ private ClientHttpResponse forward(RibbonCommandContext context) throws GatewayException {
|
|
|
+ Map<String,Object> info = null;
|
|
|
+ try {
|
|
|
+ info = this.helper.debug(context.getMethod(),
|
|
|
+ context.getUri(),
|
|
|
+ context.getHeaders(),
|
|
|
+ context.getParams(), context.getRequestEntity());
|
|
|
+ RibbonCommand command = this.ribbonCommandFactory.create(context);
|
|
|
+ ClientHttpResponse response = command.execute();
|
|
|
+ this.helper.appendDebug(info, response.getStatusCode().value(), response.getHeaders());
|
|
|
+ return response;
|
|
|
+ }catch (HystrixRuntimeException e) {
|
|
|
+ return handleException(info,e);
|
|
|
+ }catch (Exception e) {
|
|
|
+ throw new GatewayException(HttpStatus.BAD_GATEWAY,CommonMessage.Service_Error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理异常
|
|
|
+ * @param info
|
|
|
+ * @param ex
|
|
|
+ * @return
|
|
|
+ * @throws GatewayException
|
|
|
+ */
|
|
|
+ private ClientHttpResponse handleException(Map<String, Object> info, HystrixRuntimeException ex) throws GatewayException {
|
|
|
+ HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
|
+ ClientException clientException = findClientException(ex);
|
|
|
+ if(clientException == null) {
|
|
|
+ clientException = findClientException(ex.getFallbackException());
|
|
|
+ }
|
|
|
+ if(clientException != null) {
|
|
|
+ if(clientException.getErrorType() == ClientException.ErrorType.SERVER_THROTTLED) {
|
|
|
+ status = HttpStatus.SERVICE_UNAVAILABLE;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.error(">>> Netflix Client Exception-[{}]:{}",clientException.getErrorType(),clientException);
|
|
|
+
|
|
|
+ switch (clientException.getErrorType()) {
|
|
|
+ case GENERAL:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_GENERAL);
|
|
|
+ case CONFIGURATION:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_CONFIGURATION);
|
|
|
+ case NUMBEROF_RETRIES_EXEEDED:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_NUMBEROF_RETRIES_EXEEDED);
|
|
|
+ case NUMBEROF_RETRIES_NEXTSERVER_EXCEEDED:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_NUMBEROF_RETRIES_NEXTSERVER_EXCEEDED);
|
|
|
+ case SOCKET_TIMEOUT_EXCEPTION:
|
|
|
+ info.put("status", String.valueOf(HttpStatus.GATEWAY_TIMEOUT.value()));
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_SOCKET_TIMEOUT_EXCEPTION);
|
|
|
+ case READ_TIMEOUT_EXCEPTION:
|
|
|
+ info.put("status", String.valueOf(HttpStatus.GATEWAY_TIMEOUT.value()));
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_READ_TIMEOUT_EXCEPTION);
|
|
|
+ case UNKNOWN_HOST_EXCEPTION:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_UNKNOWN_HOST_EXCEPTION);
|
|
|
+ case CONNECT_EXCEPTION:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_CONNECT_EXCEPTION);
|
|
|
+ case CLIENT_THROTTLED:
|
|
|
+ info.put("status", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_CLIENT_THROTTLED);
|
|
|
+ case SERVER_THROTTLED:
|
|
|
+ info.put("status", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_SERVER_THROTTLED);
|
|
|
+ case NO_ROUTE_TO_HOST_EXCEPTION:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_NO_ROUTE_TO_HOST_EXCEPTION);
|
|
|
+ case CACHE_MISSING:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_CACHE_MISSING);
|
|
|
+ default:
|
|
|
+ throw new GatewayException(status,CommonMessage.Unkown);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!info.containsKey("status")) {
|
|
|
+ info.put("status",String.valueOf(status.value()));
|
|
|
+ }
|
|
|
+
|
|
|
+ log.error(">>> Hystrix Command Exception-[{}]:{}",ex.getFailureType(),ex.getMessage());
|
|
|
+ switch (ex.getFailureType()) {
|
|
|
+ case BAD_REQUEST_EXCEPTION:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_BAD_REQUEST_EXCEPTION);
|
|
|
+ case COMMAND_EXCEPTION:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_COMMAND_EXCEPTION);
|
|
|
+ case TIMEOUT:
|
|
|
+ info.put("status", String.valueOf(HttpStatus.GATEWAY_TIMEOUT.value()));
|
|
|
+ throw new GatewayException(HttpStatus.GATEWAY_TIMEOUT, GatewayMessage.Gateway_Exception_TIMEOUT);
|
|
|
+ case SHORTCIRCUIT:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_SHORTCIRCUIT);
|
|
|
+ case REJECTED_SEMAPHORE_EXECUTION:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_REJECTED_SEMAPHORE_EXECUTION);
|
|
|
+ case REJECTED_THREAD_EXECUTION:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_REJECTED_THREAD_EXECUTION);
|
|
|
+ case REJECTED_SEMAPHORE_FALLBACK:
|
|
|
+ throw new GatewayException(status, GatewayMessage.Gateway_Exception_REJECTED_SEMAPHORE_FALLBACK);
|
|
|
+ default:
|
|
|
+ throw new GatewayException(status,CommonMessage.Unkown);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理clientException异常
|
|
|
+ * @param t
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private ClientException findClientException(Throwable t) {
|
|
|
+ if(t ==null ) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if(t instanceof ClientException) {
|
|
|
+ return (ClientException) t;
|
|
|
+ }
|
|
|
+ return findClientException(t.getCause());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理响应消息
|
|
|
+ * @param response
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ private void setResponse(ClientHttpResponse response) throws IOException {
|
|
|
+ RequestContext.getCurrentContext().set("zuulResponse",response);
|
|
|
+ this.helper.setResponse(response.getStatusCode().value(),
|
|
|
+ response.getBody(),
|
|
|
+ response.getHeaders());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理异常响应消息
|
|
|
+ * @param e
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Response buildExceptionResponse(Exception e) {
|
|
|
+ Response response = new Response();
|
|
|
+ response.setRequestId("服务追踪的traceId://todo");
|
|
|
+
|
|
|
+ String message = "";
|
|
|
+ if(e instanceof GatewayException) {
|
|
|
+ GatewayException ge = (GatewayException) e;
|
|
|
+ message = ge.getMessage();
|
|
|
+ response.setMessage(message);
|
|
|
+ response.setCode(ge.getCode());
|
|
|
+ response.setHttpCode(ge.getHttpstatus().value());
|
|
|
+ RequestContext.getCurrentContext().setResponseStatusCode(ge.getHttpstatus().value());
|
|
|
+ }else {
|
|
|
+ message = e.getMessage();
|
|
|
+ response.setMessage(message);
|
|
|
+ response.setCode(CommonMessage.Internal_Error);
|
|
|
+ RequestContext.getCurrentContext().setResponseStatusCode(HttpStatus.BAD_GATEWAY.value());
|
|
|
+ }
|
|
|
+ RequestContext.getCurrentContext().set("zuulResponse",response);
|
|
|
+ String body = JSON.toJSONString(response,pascalFilter,SerializerFeature.PrettyFormat);
|
|
|
+ RequestContext.getCurrentContext().setResponseBody(body);
|
|
|
+ RequestContext.getCurrentContext().setSendZuulResponse(false);
|
|
|
+ RequestContext.getCurrentContext().addZuulResponseHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构造请求体内容
|
|
|
+ * @param context
|
|
|
+ * @param command
|
|
|
+ * @return
|
|
|
+ * @throws GatewayException
|
|
|
+ */
|
|
|
+ private RibbonCommandContext buildCommandContext(RequestContext context, String command) throws GatewayException {
|
|
|
+ HttpServletRequest request = context.getRequest();
|
|
|
+ MultiValueMap<String, String> headers = helper.buildZuulRequestHeaders(request);
|
|
|
+ MultiValueMap<String, String> params = helper.buildZuulRequestQueryParams(request);
|
|
|
+ InputStream requestEntity = getRequestBody(request);
|
|
|
+ if(request.getContentLength()<0) {
|
|
|
+ context.setChunkedRequestBody();
|
|
|
+ }
|
|
|
+
|
|
|
+ Boolean retryable = context.getBoolean("retryable");
|
|
|
+
|
|
|
+ String serviceId = null;
|
|
|
+ String uri = null;
|
|
|
+ if(StringUtils.isEmpty(command)) {
|
|
|
+ //restful风格api请求
|
|
|
+ String originalUri = request.getRequestURI();
|
|
|
+ String uriPrefix = getUriPrefix(originalUri);
|
|
|
+ uri = originalUri.replace("//", "/").substring(uriPrefix.length());
|
|
|
+ log.debug(">>> uri:[{}],original uri:[{}],prefix:[{}].",uri,originalUri,uriPrefix);
|
|
|
+ serviceId = this.getRestService(originalUri);
|
|
|
+ log.debug(">>> 请求类型为RESTful模式,转发URI:[{}],原始URI:[{}].",uri,originalUri);
|
|
|
+ }else {
|
|
|
+ uri = GatewayConstans.COMMAND_API;
|
|
|
+
|
|
|
+ //获取command模式的serviceId
|
|
|
+ serviceId = this.getCommandService(command);
|
|
|
+ log.debug(">>> 请求类型为command模式(action),转发URI:[{}]",uri);
|
|
|
+ log.debug(">>> 请求Action:[{}].",command);
|
|
|
+ }
|
|
|
+ if(serviceId==null) {
|
|
|
+ log.debug(">>> 服务注册中心未找到该请求对应的服务,终止转发。");
|
|
|
+ RequestContext.getCurrentContext().setResponseStatusCode(HttpStatus.BAD_GATEWAY.value());
|
|
|
+ RequestContext.getCurrentContext().setSendZuulResponse(false);
|
|
|
+ throw new GatewayException(HttpStatus.BAD_GATEWAY,CommonMessage.Invalid_Parameter_Action_Error);
|
|
|
+ }
|
|
|
+
|
|
|
+ //如果yaml配置文件中能找到当前的Service就以当前的为准,否则以数据库中的为准
|
|
|
+ serviceId = (service.get(serviceId)!=null)?service.get(serviceId):serviceId;
|
|
|
+
|
|
|
+ //检查是否有服务可以用
|
|
|
+ log.debug(">>> 检查是否有可用的服务[{}]可以转发...",serviceId);
|
|
|
+ this.checkLoadblanceActive(serviceId);
|
|
|
+ log.debug(">>> 找到可供转发的后台服务[{}].",serviceId);
|
|
|
+ log.debug(">>> 请求转发到[{}]后台服务.",serviceId);
|
|
|
+
|
|
|
+ RequestContext.getCurrentContext().set("serviceId",serviceId);
|
|
|
+
|
|
|
+ long contextLength = useServlet31?request.getContentLengthLong():request.getContentLength();
|
|
|
+
|
|
|
+ //构造Ribbon请求上下文
|
|
|
+ return new RibbonCommandContext(serviceId,
|
|
|
+ getMethod(request),
|
|
|
+ uri,
|
|
|
+ retryable,
|
|
|
+ headers,
|
|
|
+ params,
|
|
|
+ requestEntity,
|
|
|
+ this.requestCustomizers,
|
|
|
+ contextLength);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取command类型的服务id
|
|
|
+ * @param command
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getCommandService(String command) throws GatewayException {
|
|
|
+// ActionDTO actionDto = null;
|
|
|
+// String key = RedisKeyPrefix.getKey(RedisKeyPrefix.GATEWAY,"command",command);
|
|
|
+// String serviceId = (String) redisUtil.get(key);
|
|
|
+// if(StringUtils.isEmpty(serviceId)) {
|
|
|
+// //如果缓存中没有就重新加载
|
|
|
+// actionDto = configService.getAction(command);
|
|
|
+// if(actionDto!=null) {
|
|
|
+// serviceId = actionDto.getServiceCode();
|
|
|
+// //重新加载缓存起来
|
|
|
+// redisUtil.set(key, serviceId);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// return serviceId;
|
|
|
+ //暂不支持command模式
|
|
|
+ throw new GatewayException(HttpStatus.BAD_GATEWAY,CommonMessage.Invalid_Parameter_Action_Error);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取restful类型的服务id
|
|
|
+ * @param uri
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getRestService(String uri) {
|
|
|
+ if(uri.startsWith(GatewayConstans.RESTFUL_PREFIX)) {
|
|
|
+ String uriPrefix = getUriPrefix(uri);
|
|
|
+ String serviceId = uriPrefix.substring(uriPrefix.lastIndexOf("/")+1);
|
|
|
+// ServiceDTO serviceDto = null;
|
|
|
+// String key = RedisKeyPrefix.getKey(RedisKeyPrefix.GATEWAY,"rest",tmpUriPrefix);
|
|
|
+// String serviceId = (String) redisUtil.get(key);
|
|
|
+// if(StringUtils.isEmpty(serviceId)) {
|
|
|
+// //如果缓存中没有就重新加载
|
|
|
+// serviceDto = configService.getService(tmpUriPrefix);
|
|
|
+// if(serviceDto!=null) {
|
|
|
+// serviceId = serviceDto.getServiceCode();
|
|
|
+// //重新加载缓存起来
|
|
|
+// redisUtil.set(key, serviceId);
|
|
|
+// }
|
|
|
+// }
|
|
|
+ return serviceId;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析请求消息体,转化为流
|
|
|
+ * @param request
|
|
|
+ * @return
|
|
|
+ * @throws GatewayException
|
|
|
+ */
|
|
|
+ private InputStream getRequestBody(HttpServletRequest request) throws GatewayException {
|
|
|
+ InputStream requestEntity = null;
|
|
|
+ try {
|
|
|
+ requestEntity = (InputStream) RequestContext.getCurrentContext().get(FilterConstants.REQUEST_ENTITY_KEY);
|
|
|
+ if(requestEntity == null) {
|
|
|
+ requestEntity = request.getInputStream();
|
|
|
+ }
|
|
|
+ }catch (Exception e) {
|
|
|
+ throw new GatewayException(HttpStatus.BAD_GATEWAY,CommonMessage.Parameter_Validate_Parsing_Error);
|
|
|
+ }
|
|
|
+ return requestEntity;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查服务是否可用
|
|
|
+ * 主要解决问题是服务首次启动后,立刻访问网关时
|
|
|
+ * 网关还未更新服务注册表,导致找不到服务的问题
|
|
|
+ * @param serviceId
|
|
|
+ * @throws GatewayException
|
|
|
+ */
|
|
|
+ private void checkLoadblanceActive(String serviceId) throws GatewayException {
|
|
|
+ try {
|
|
|
+ int count = 0;
|
|
|
+ while(loadBalancer.choose(serviceId)==null && count < chooseRetryCount*60) {
|
|
|
+ count++;
|
|
|
+ Thread.sleep(1000);//每尝试一次,间隔1秒
|
|
|
+ }
|
|
|
+
|
|
|
+ if(loadBalancer.choose(serviceId)==null) {
|
|
|
+ log.debug(">>> 未找到可供转发的后台服务[{}].",serviceId);
|
|
|
+ throw new GatewayException(HttpStatus.NOT_FOUND, GatewayMessage.Gateway_Exception_Service_UnknownHost);
|
|
|
+ }
|
|
|
+ }catch (Exception e) {
|
|
|
+ log.debug(">>> 检查是否有可用服务[{}]出错:{}",serviceId,e.getMessage());
|
|
|
+ throw new GatewayException(HttpStatus.NOT_FOUND, GatewayMessage.Gateway_Exception_NOT_CHOOSE_SERVICE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取请求方法
|
|
|
+ * @param request
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getMethod(HttpServletRequest request) {
|
|
|
+ String method = request.getMethod();
|
|
|
+ if(method == null) {
|
|
|
+ method = "GET";
|
|
|
+ }
|
|
|
+ return method;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取请求前缀
|
|
|
+ * @param uri
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getUriPrefix(String uri) {
|
|
|
+ String uriPrefix = "";
|
|
|
+ if(uri.startsWith(GatewayConstans.COMMAND_PREFIX)) {
|
|
|
+ //command
|
|
|
+ StringBuffer sb = new StringBuffer();
|
|
|
+ sb.append(GatewayConstans.COMMAND_PREFIX).append("/");
|
|
|
+ String temp = uri.substring(sb.toString().length());
|
|
|
+ String version = temp.substring(0,temp.indexOf("/"));
|
|
|
+ sb.append(version);
|
|
|
+
|
|
|
+ uriPrefix = sb.toString();
|
|
|
+ }else if(uri.startsWith(GatewayConstans.RESTFUL_PREFIX)) {
|
|
|
+ //restful
|
|
|
+ StringBuffer sb = new StringBuffer();
|
|
|
+ sb.append(GatewayConstans.RESTFUL_PREFIX).append("/");
|
|
|
+ String tmp = uri.substring(sb.toString().length());
|
|
|
+ String version = tmp.substring(0,tmp.indexOf("/")+1);
|
|
|
+ sb.append(version);
|
|
|
+ tmp = uri.substring(sb.toString().length());
|
|
|
+ tmp = tmp.replace("?", "/");
|
|
|
+ String product = tmp.substring(0,tmp.indexOf("/"));
|
|
|
+ sb.append(product);
|
|
|
+
|
|
|
+ uriPrefix = sb.toString();
|
|
|
+ }
|
|
|
+ return uriPrefix;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|