package com.moon.server.helper; import com.moon.server.entity.all.StaticData; import com.moon.server.entity.sys.ResEntity; import org.apache.http.*; import org.apache.http.client.config.CookieSpecs; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.utils.URIUtils; import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.message.BasicHttpRequest; import org.apache.http.message.HeaderGroup; import org.apache.http.util.EntityUtils; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.HttpCookie; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.Enumeration; /** * Http帮助类 * @author WWW */ public class HttpHelper { private final static String HTTP_SLASH2 = "://"; private final static String HTTP_SLASH = "/"; private final static Integer THREE = 3; protected static final HeaderGroup HOP_HEADERS; static { HOP_HEADERS = new HeaderGroup(); String[] headers = new String[]{ "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", "TE", "Trailers", "Transfer-Encoding", "Upgrade", //"X-RateLimit-Burst-Capacity", "X-RateLimit-Remaining", "X-RateLimit-Replenish-Rate", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials", "Access-Control-Allow-Headers"}; for (String header : headers) { HOP_HEADERS.addHeader(new BasicHeader(header, null)); } } public void service(HttpServletRequest request, HttpServletResponse response, ResEntity entity, String url) throws ServletException, IOException { HttpRequest proxyRequest; if (request.getHeader(HttpHeaders.CONTENT_LENGTH) != null || request.getHeader(HttpHeaders.TRANSFER_ENCODING) != null) { proxyRequest = newProxyRequestWithEntity(request, url); } else { proxyRequest = new BasicHttpRequest(request.getMethod(), url); } HttpHost host = this.getTargetHost(url); // copyRequestHeaders(request, proxyRequest, host); //setXrForwardedForHeader(request, proxyRequest); // if (!StringHelper.isEmpty(cookie)) proxyRequest.addHeader("Cookie", cookie + "; ") CloseableHttpClient client = null; HttpResponse proxyResponse = null; try { client = this.createHttpClient(); proxyResponse = client.execute(host, proxyRequest); int statusCode = proxyResponse.getStatusLine().getStatusCode(); // response.setStatus(statusCode, proxyResponse.getStatusLine().getReasonPhrase()) response.setStatus(statusCode); copyResponseHeaders(proxyResponse, request, response, url); if (statusCode == HttpServletResponse.SC_NOT_MODIFIED) { response.setIntHeader(HttpHeaders.CONTENT_LENGTH, 0); } else { copyResponseEntity(proxyResponse, request, response, entity); } } catch (Exception ex) { throw new ServletException(ex.getMessage()); } finally { if (proxyResponse != null) { EntityUtils.consumeQuietly(proxyResponse.getEntity()); } if (client != null) { client.close(); } } } protected HttpRequest newProxyRequestWithEntity(HttpServletRequest request, String url) throws IOException { String method = request.getMethod(); HttpEntityEnclosingRequest proxyRequest = new BasicHttpEntityEnclosingRequest(method, url); proxyRequest.setEntity(new InputStreamEntity(request.getInputStream(), getContentLength(request))); //String str = EntityUtils.toString(proxyRequest.getEntity(), "UTF-8") return proxyRequest; } private long getContentLength(HttpServletRequest request) { String contentLengthHeader = request.getHeader("Content-Length"); if (contentLengthHeader != null) { return Long.parseLong(contentLengthHeader); } return -1L; } protected void copyRequestHeaders(HttpServletRequest request, HttpRequest proxyRequest, HttpHost host) { @SuppressWarnings("unchecked") Enumeration enumerationOfHeaderNames = request.getHeaderNames(); while (enumerationOfHeaderNames.hasMoreElements()) { String headerName = enumerationOfHeaderNames.nextElement(); copyRequestHeader(request, proxyRequest, host, headerName); } } protected void copyRequestHeader(HttpServletRequest request, HttpRequest proxyRequest, HttpHost host, String headerName) { if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH) || HOP_HEADERS.containsHeader(headerName)) { return; } @SuppressWarnings("unchecked") Enumeration headers = request.getHeaders(headerName); while (headers.hasMoreElements()) { String headerValue = headers.nextElement(); if (headerName.equalsIgnoreCase(HttpHeaders.HOST)) { headerValue = host.getHostName(); if (host.getPort() != -1) { headerValue += ":" + host.getPort(); } } else if (headerName.equalsIgnoreCase(org.apache.http.cookie.SM.COOKIE)) { headerValue = getRealCookie(headerValue); } proxyRequest.addHeader(headerName, headerValue); } } protected HttpHost getTargetHost(String url) throws ServletException { try { URI uri = new URI(url); return URIUtils.extractHost(uri); } catch (URISyntaxException ex) { throw new ServletException(ex.getMessage()); } } protected String getRealCookie(String cookieValue) { StringBuilder escapedCookie = new StringBuilder(); String[] cookies = cookieValue.split("[;,]"); for (String cookie : cookies) { String[] cookieSplit = cookie.split("="); if (cookieSplit.length == 2) { String cookieName = cookieSplit[0].trim(); if (cookieName.startsWith(cookieName)) { cookieName = cookieName.substring(cookieName.length()); if (escapedCookie.length() > 0) { escapedCookie.append("; "); } escapedCookie.append(cookieName).append("=").append(cookieSplit[1].trim()); } } } return escapedCookie.toString(); } private void setXrForwardedForHeader(HttpServletRequest request, HttpRequest proxyRequest) { String forHeaderName = "X-Forwarded-For"; String forHeader = request.getRemoteAddr(); String existingForHeader = request.getHeader(forHeaderName); if (existingForHeader != null) { forHeader = existingForHeader + ", " + forHeader; } proxyRequest.setHeader(forHeaderName, forHeader); String protoHeaderName = "X-Forwarded-Proto"; String protoHeader = request.getScheme(); proxyRequest.setHeader(protoHeaderName, protoHeader); } protected CloseableHttpClient createHttpClient() { RequestConfig requestConfig = RequestConfig.custom() .setRedirectsEnabled(false) .setCookieSpec(CookieSpecs.IGNORE_COOKIES) .setConnectTimeout(-1) .setSocketTimeout(-1) .build(); // return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build() return HttpClients.custom() .setDefaultRequestConfig(requestConfig) .build(); } protected void copyResponseHeaders(HttpResponse proxyResponse, HttpServletRequest request, HttpServletResponse response, String url) { for (Header header : proxyResponse.getAllHeaders()) { copyResponseHeader(request, response, header, url); } } protected void copyResponseHeader(HttpServletRequest request, HttpServletResponse response, Header header, String url) { String headerName = header.getName(); if (HOP_HEADERS.containsHeader(headerName)) { return; } String headerValue = header.getValue(); if (headerName.equalsIgnoreCase(org.apache.http.cookie.SM.SET_COOKIE) || headerName.equalsIgnoreCase(org.apache.http.cookie.SM.SET_COOKIE2)) { copyProxyCookie(request, response, headerValue); } else if (headerName.equalsIgnoreCase(HttpHeaders.LOCATION)) { response.addHeader(headerName, rewriteUrlFromResponse(request, url, headerValue)); } else { response.addHeader(headerName, headerValue); } } protected void copyProxyCookie(HttpServletRequest request, HttpServletResponse response, String headerValue) { String path = request.getContextPath() + request.getServletPath(); if (path.isEmpty()) { path = "/"; } for (HttpCookie cookie : HttpCookie.parse(headerValue)) { Cookie servletCookie = new Cookie(cookie.getName(), cookie.getValue()); servletCookie.setComment(cookie.getComment()); servletCookie.setMaxAge((int) cookie.getMaxAge()); servletCookie.setPath(path); servletCookie.setSecure(cookie.getSecure()); servletCookie.setVersion(cookie.getVersion()); response.addCookie(servletCookie); } } protected String rewriteUrlFromResponse(HttpServletRequest request, String targetUri, String theUrl) { if (theUrl.startsWith(targetUri)) { StringBuffer curUrl = request.getRequestURL(); int pos; if ((pos = curUrl.indexOf(HTTP_SLASH2)) >= 0) { if ((pos = curUrl.indexOf(HTTP_SLASH, pos + THREE)) >= 0) { curUrl.setLength(pos); } } curUrl.append(request.getContextPath()); curUrl.append(request.getServletPath()); curUrl.append(theUrl, targetUri.length(), theUrl.length()); return curUrl.toString(); } return theUrl; } protected void copyResponseEntity(HttpResponse proxyResponse, HttpServletRequest request, HttpServletResponse response, ResEntity res) throws IOException { HttpEntity entity = proxyResponse.getEntity(); if (null == entity) { return; } switch (res.getCategory()) { case 2: copeGeoService(proxyResponse, request, response, res); break; case 3: copeSjService(proxyResponse, request, response, res); break; default: entity.writeTo(response.getOutputStream()); break; } } private void copeGeoService(HttpResponse proxyResponse, HttpServletRequest request, HttpServletResponse response, ResEntity res) throws IOException { if (!StaticData.GET_CAPABILITIES.equals(res.getBak())) { proxyResponse.getEntity().writeTo(response.getOutputStream()); return; } String str = EntityUtils.toString(proxyResponse.getEntity(), "UTF-8"); String proxyUrl = res.getProxy().replace("{token}", response.getHeader("token")); proxyUrl = request.getRequestURL().substring(0, request.getRequestURL().indexOf(proxyUrl) + proxyUrl.length()); str = str.replace(res.getUrl(), proxyUrl); int index = str.indexOf(StaticData.QUERYABLE); while (index > -1) { int start = str.indexOf("", index) + StaticData.I6; int end = str.indexOf("", index) + StaticData.I8; String name = ":" + str.substring(start, str.indexOf("", start)); if (!res.getTab().contains(name)) { // index = str.lastIndexOf(">", index) end = str.indexOf("<", end); str = str.substring(0, index) + str.substring(end); index = str.indexOf(StaticData.QUERYABLE, index); } else { index = str.indexOf(StaticData.QUERYABLE, end); } } byte[] bytes = str.getBytes(StandardCharsets.UTF_8); response.setContentLength(bytes.length); response.getOutputStream().write(bytes); } private void copeSjService(HttpResponse proxyResponse, HttpServletRequest request, HttpServletResponse response, ResEntity res) throws IOException { Header[] headers = proxyResponse.getHeaders("content-type"); if (null != headers && headers.length > 0 && headers[0].getValue().contains(StaticData.TEXT_XML)) { String str = filterStr(request, response, res, EntityUtils.toString(proxyResponse.getEntity(), "UTF-8")); byte[] bytes = str.getBytes(StandardCharsets.UTF_8); response.setContentLength(bytes.length); response.getOutputStream().write(bytes); } else { proxyResponse.getEntity().writeTo(response.getOutputStream()); } } private String filterStr(HttpServletRequest request, HttpServletResponse response, ResEntity res, String str) { if (str.contains(res.getUrl())) { String proxyUrl = res.getProxy().replace("{token}", response.getHeader("token")); proxyUrl = request.getRequestURL().substring(0, request.getRequestURL().indexOf(proxyUrl) + proxyUrl.length()); str = str.replace(res.getUrl(), proxyUrl); if (!StringHelper.isEmpty(res.getArgs())) { // str = str.replace("?" + res.getArgs(), "").replace("&" + res.getArgs(), "") str = str.replace("?" + res.getArgs() + "\"", "\"").replace("&" + res.getArgs() + "\"", "\"") .replace("?" + res.getArgs() + "&", "?").replace("&" + res.getArgs() + "&", "&"); } if (StaticData.I3 == res.getCategory() && str.contains(StaticData.REST_LAYER)) { str = str.replace(res.getUrl().replace("/v6/wmts/", StaticData.REST_LAYER), proxyUrl.replace("/proxy/", "/proxy/rest/")); } } return str; } }