001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.components.gateway; 017 018import com.jfinal.kit.Ret; 019import io.jboot.Jboot; 020import io.jboot.utils.StrUtil; 021import io.jboot.web.render.JbootJsonRender; 022 023import javax.servlet.http.HttpServletRequest; 024import javax.servlet.http.HttpServletResponse; 025import java.net.ConnectException; 026 027 028public class GatewayInvocation { 029 030 private JbootGatewayConfig config; 031 private GatewayInterceptor[] inters; 032 private HttpServletRequest request; 033 private HttpServletResponse response; 034 private GatewayHttpProxy proxy; 035 private String proxyUrl; 036 037 //是否跳过错误渲染,如果跳过,那么则由拦截器通过 getResponse() 自行渲染 038 private boolean skipExceptionRender = false; 039 040 private static boolean devMode = Jboot.isDevMode(); 041 042 private int index = 0; 043 044 045 public GatewayInvocation(JbootGatewayConfig config, HttpServletRequest request, HttpServletResponse response) { 046 this.config = config; 047 this.request = request; 048 this.response = response; 049 this.inters = config.getGatewayInterceptors(); 050 this.proxy = new GatewayHttpProxy(config); 051 this.proxyUrl = buildProxyUrl(config, request); 052 } 053 054 055 public void invoke() { 056 if (inters.length == 0) { 057 doInvoke(); 058 return; 059 } 060 if (index < inters.length) { 061 inters[index++].intercept(this); 062 } else if (index++ >= inters.length) { 063 doInvoke(); 064 } 065 } 066 067 068 protected void doInvoke() { 069 if (StrUtil.isBlank(proxyUrl)) { 070 renderError(null, GatewayErrorRender.noneHealthUrl, config, request, response); 071 return; 072 } 073 074 if (devMode) { 075 System.out.println("Jboot Gateway >>> " + proxyUrl); 076 } 077 078 //启用 Sentinel 限流 079 if (config.isSentinelEnable()) { 080 new GatewaySentinelProcesser().process(proxy, proxyUrl, config, request, response, skipExceptionRender); 081 }else { 082 083 //未启用 Sentinel 的情况 084 proxy.sendRequest(proxyUrl, request, response); 085 086 Exception exception = proxy.getException(); 087 if (exception != null && !skipExceptionRender) { 088 if (exception instanceof ConnectException) { 089 Ret connectionError = Ret.fail().set("errorCode", 2).set("message", "Can not connect to target server: " + proxyUrl); 090 renderError(exception, connectionError, config, request, response); 091 } else { 092 Ret ret = Ret.fail().set("errorCode", 9).set("message", exception.getMessage()); 093 renderError(exception, ret, config, request, response); 094 } 095 } 096 } 097 098 } 099 100 101 private static void renderError(Exception error, Ret errorMessage, JbootGatewayConfig config, HttpServletRequest request, HttpServletResponse response) { 102 GatewayErrorRender errorRender = JbootGatewayManager.me().getGatewayErrorRender(); 103 if (errorRender != null) { 104 errorRender.renderError(error, errorMessage, config, request, response); 105 } else { 106 new JbootJsonRender(errorMessage).setContext(request, response).render(); 107 } 108 } 109 110 111 private static String buildProxyUrl(JbootGatewayConfig config, HttpServletRequest request) { 112 //配置负载均衡策略 113 GatewayLoadBalanceStrategy lbs = config.buildLoadBalanceStrategy(); 114 115 //通过负载均衡策略获取 URL 地址 116 String url = lbs.getUrl(config, request); 117 if (StrUtil.isBlank(url)) { 118 return null; 119 } 120 121 StringBuilder sb = new StringBuilder(url); 122 if (StrUtil.isNotBlank(request.getRequestURI())) { 123 sb.append(request.getRequestURI()); 124 } 125 126 if (StrUtil.isNotBlank(request.getQueryString())) { 127 sb.append("?").append(request.getQueryString()); 128 } 129 130 return sb.toString(); 131 } 132 133 134 public JbootGatewayConfig getConfig() { 135 return config; 136 } 137 138 public void setConfig(JbootGatewayConfig config) { 139 this.config = config; 140 } 141 142 public GatewayInterceptor[] getInters() { 143 return inters; 144 } 145 146 public void setInters(GatewayInterceptor[] inters) { 147 this.inters = inters; 148 } 149 150 public HttpServletRequest getRequest() { 151 return request; 152 } 153 154 public void setRequest(HttpServletRequest request) { 155 this.request = request; 156 } 157 158 public HttpServletResponse getResponse() { 159 return response; 160 } 161 162 public void setResponse(HttpServletResponse response) { 163 this.response = response; 164 } 165 166 public int getIndex() { 167 return index; 168 } 169 170 public void setIndex(int index) { 171 this.index = index; 172 } 173 174 public GatewayHttpProxy getProxy() { 175 return proxy; 176 } 177 178 179 public void setProxy(GatewayHttpProxy proxy) { 180 this.proxy = proxy; 181 } 182 183 public boolean hasException() { 184 return proxy.getException() != null; 185 } 186 187 public String getProxyUrl() { 188 return proxyUrl; 189 } 190 191 public void setProxyUrl(String proxyUrl) { 192 this.proxyUrl = proxyUrl; 193 } 194 195 public boolean isSkipExceptionRender() { 196 return skipExceptionRender; 197 } 198 199 public void setSkipExceptionRender(boolean skipExceptionRender) { 200 this.skipExceptionRender = skipExceptionRender; 201 } 202}