sequence
In this paper, we look nacos of DistroFilter
CanDistro
nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/web/CanDistro.java
@Retention(RetentionPolicy.RUNTIME)
public @interface CanDistro {
}
复制代码
- A method for identifying a need to determine whether CanDistro should be redirected according distro
DistroFilter
nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/web/DistroFilter.java
public class DistroFilter implements Filter {
private static final int PROXY_CONNECT_TIMEOUT = 2000;
private static final int PROXY_READ_TIMEOUT = 2000;
@Autowired
private DistroMapper distroMapper;
@Autowired
private SwitchDomain switchDomain;
@Autowired
private FilterBase filterBase;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String urlString = req.getRequestURI();
if (StringUtils.isNotBlank(req.getQueryString())) {
urlString += "?" + req.getQueryString();
}
try {
String path = new URI(req.getRequestURI()).getPath();
String serviceName = req.getParameter(CommonParams.SERVICE_NAME);
// For client under 0.8.0:
if (StringUtils.isBlank(serviceName)) {
serviceName = req.getParameter("dom");
}
Method method = filterBase.getMethod(req.getMethod(), path);
if (method == null) {
throw new NoSuchMethodException(req.getMethod() + " " + path);
}
String groupName = req.getParameter(CommonParams.GROUP_NAME);
if (StringUtils.isBlank(groupName)) {
groupName = Constants.DEFAULT_GROUP;
}
// use groupName@@serviceName as new service name:
String groupedServiceName = serviceName;
if (StringUtils.isNotBlank(serviceName) && !serviceName.contains(Constants.SERVICE_INFO_SPLITER)) {
groupedServiceName = groupName + Constants.SERVICE_INFO_SPLITER + serviceName;
}
// proxy request to other server if necessary:
if (method.isAnnotationPresent(CanDistro.class) && !distroMapper.responsible(groupedServiceName)) {
String userAgent = req.getHeader("User-Agent");
if (StringUtils.isNotBlank(userAgent) && userAgent.contains(UtilsAndCommons.NACOS_SERVER_HEADER)) {
// This request is sent from peer server, should not be redirected again:
Loggers.SRV_LOG.error("receive invalid redirect request from peer {}", req.getRemoteAddr());
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"receive invalid redirect request from peer " + req.getRemoteAddr());
return;
}
List<String> headerList = new ArrayList<>(16);
Enumeration<String> headers = req.getHeaderNames();
while (headers.hasMoreElements()) {
String headerName = headers.nextElement();
headerList.add(headerName);
headerList.add(req.getHeader(headerName));
}
HttpClient.HttpResult result =
HttpClient.request("http://" + distroMapper.mapSrv(groupedServiceName) + urlString, headerList,
StringUtils.isBlank(req.getQueryString()) ? HttpClient.translateParameterMap(req.getParameterMap()) : new HashMap<>(2)
, PROXY_CONNECT_TIMEOUT, PROXY_READ_TIMEOUT, "UTF-8", req.getMethod());
try {
resp.setCharacterEncoding("UTF-8");
resp.getWriter().write(result.content);
resp.setStatus(result.code);
} catch (Exception ignore) {
Loggers.SRV_LOG.warn("[DISTRO-FILTER] request failed: " + distroMapper.mapSrv(groupedServiceName) + urlString);
}
return;
}
OverrideParameterRequestWrapper requestWrapper = OverrideParameterRequestWrapper.buildRequest(req);
requestWrapper.addParameter(CommonParams.SERVICE_NAME, groupedServiceName);
filterChain.doFilter(requestWrapper, resp);
} catch (AccessControlException e) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "access denied: " + UtilsAndCommons.getAllExceptionMsg(e));
return;
} catch (NoSuchMethodException e) {
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "no such api: " + e.getMessage());
return;
} catch (Exception e) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Server failed," + UtilsAndCommons.getAllExceptionMsg(e));
return;
}
}
@Override
public void destroy() {
}
}
复制代码
- DistroFilter implements the servlet Filter interface; it doFilter method reads serviceName, method, groupName, etc. from servletRequest, and then determine whether the labeling method CanDistro, if it is not responsible for the service and distroMapper the building http request is then written back Filter results; If you do not redirect continue filterChain.doFilter
HttpClient.request
nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/misc/HttpClient.java
public class HttpClient {
private static final int TIME_OUT_MILLIS = 10000;
private static final int CON_TIME_OUT_MILLIS = 5000;
private static AsyncHttpClient asyncHttpClient;
private static CloseableHttpClient postClient;
//......
public static HttpResult request(String url, List<String> headers, Map<String, String> paramValues, int connectTimeout, int readTimeout, String encoding, String method) {
HttpURLConnection conn = null;
try {
String encodedContent = encodingParams(paramValues, encoding);
url += (null == encodedContent) ? "" : ("?" + encodedContent);
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(connectTimeout);
conn.setReadTimeout(readTimeout);
conn.setRequestMethod(method);
conn.addRequestProperty("Client-Version", UtilsAndCommons.SERVER_VERSION);
conn.addRequestProperty("User-Agent", UtilsAndCommons.SERVER_VERSION);
setHeaders(conn, headers, encoding);
conn.connect();
return getResult(conn);
} catch (Exception e) {
Loggers.SRV_LOG.warn("Exception while request: {}, caused: {}", url, e);
return new HttpResult(500, e.toString(), Collections.<String, String>emptyMap());
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
private static HttpResult getResult(HttpURLConnection conn) throws IOException {
int respCode = conn.getResponseCode();
InputStream inputStream;
if (HttpURLConnection.HTTP_OK == respCode) {
inputStream = conn.getInputStream();
} else {
inputStream = conn.getErrorStream();
}
Map<String, String> respHeaders = new HashMap<String, String>(conn.getHeaderFields().size());
for (Map.Entry<String, List<String>> entry : conn.getHeaderFields().entrySet()) {
respHeaders.put(entry.getKey(), entry.getValue().get(0));
}
String gzipEncoding = "gzip";
if (gzipEncoding.equals(respHeaders.get(HttpHeaders.CONTENT_ENCODING))) {
inputStream = new GZIPInputStream(inputStream);
}
HttpResult result = new HttpResult(respCode, IOUtils.toString(inputStream, getCharset(conn)), respHeaders);
inputStream.close();
return result;
}
public static class HttpResult {
final public int code;
final public String content;
final private Map<String, String> respHeaders;
public HttpResult(int code, String content, Map<String, String> respHeaders) {
this.code = code;
this.content = content;
this.respHeaders = respHeaders;
}
public String getHeader(String name) {
return respHeaders.get(name);
}
}
//......
}
复制代码
- The method of HttpClient request directly HttpURLConnection jdk the request and returns the result to the package HttpResult, whose content is the body's response to
summary
DistroFilter implements the servlet Filter interface; it doFilter method reads serviceName, method, groupName, etc. from servletRequest, and then determine whether the labeling method CanDistro, if it is not responsible for the service and distroMapper the building http request is then written back Filter results; If you do not redirect continue filterChain.doFilter