Zuul 路由重写 SimpleHostRoutingFilter 地址

  • 项目中需求可以自定义路由不对外暴露真实url地址
  • 例如:
    	定义一个路由为: /login
    	对应的转发的真实地址为: http://ip:port/sso/api/login
    	实际转发为:/login ->  http://ip:port/sso/api/login
    	这时候默认的路由规则 就不适用
    	
    	默认路由匹配规则:
    	/login -> /sso/api/login
    	
    	起初 直接覆写了 org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter 这个类 
    	Eclipse中运行的时候会调用覆写的类,但是打包的时候 覆写的类失效了 这里觉得应该是打包顺序问题 (实践证明不能偷懒)
    	于是直接重写了 SimpleHostRoutingFilter run 方法
    
package com.jx.zuul.server.filter;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.commons.httpclient.ApacheHttpClientConnectionManagerFactory;
import org.springframework.cloud.commons.httpclient.ApacheHttpClientFactory;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter;
import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;

import com.netflix.zuul.context.RequestContext;


/**
* @ClassName: RewriteSimpleHostRoutingFilter  
* @Description: TODO(重写SimpleHostRoutingFilter run方法)  
* @author gangyu2
* @date 2019年7月8日 下午8:02:36  
*
 */
@Component
public class RewriteSimpleHostRoutingFilter extends SimpleHostRoutingFilter {
	private static final Log log = LogFactory.getLog(RewriteSimpleHostRoutingFilter.class);
	@Autowired
	private ProxyRequestHelper helper;

	private CloseableHttpClient httpClient=null;
	
	public CloseableHttpClient instanceCloseableHttpClient() {
		if(null == httpClient) {
			CloseableHttpClient client = HttpClientBuilder.create().build();
			httpClient=client;
		}
		return httpClient;
	}
	
	public RewriteSimpleHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties properties,
			ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
			ApacheHttpClientFactory httpClientFactory) {
		super(helper, properties, connectionManagerFactory, httpClientFactory);
	}

	@Override
	public Object run() {
		RequestContext context = RequestContext.getCurrentContext();
		HttpServletRequest request = context.getRequest();
		MultiValueMap<String, String> headers = this.helper
				.buildZuulRequestHeaders(request);
		MultiValueMap<String, String> params = this.helper
				.buildZuulRequestQueryParams(request);
		String verb = getVerb(request);
		InputStream requestEntity = getRequestBody(request);
		if (getContentLength(request) < 0) {
			context.setChunkedRequestBody();
		}

		String uri = this.helper.buildZuulRequestURI(request);
		this.helper.addIgnoredHeaders();

		try {
			CloseableHttpResponse response = forward(instanceCloseableHttpClient(), verb, uri, request,
					headers, params, requestEntity);
			setResponse(response);
		}
		catch (Exception ex) {
			throw new ZuulRuntimeException(handleException(ex));
		}
		return null;
	}

	private String getVerb(HttpServletRequest request) {
		String sMethod = request.getMethod();
		return sMethod.toUpperCase();
	}
	private void setResponse(HttpResponse response) throws IOException {
		RequestContext.getCurrentContext().set("zuulResponse", response);
		this.helper.setResponse(response.getStatusLine().getStatusCode(),
				response.getEntity() == null ? null : response.getEntity().getContent(),
				revertHeaders(response.getAllHeaders()));
	}

	private MultiValueMap<String, String> revertHeaders(Header[] headers) {
		MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
		for (Header header : headers) {
			String name = header.getName();
			if (!map.containsKey(name)) {
				map.put(name, new ArrayList<String>());
			}
			map.get(name).add(header.getValue());
		}
		return map;
	}
	private CloseableHttpResponse forward(CloseableHttpClient httpclient, String verb,
			String uri, HttpServletRequest request, MultiValueMap<String, String> headers,
			MultiValueMap<String, String> params, InputStream requestEntity)
			throws Exception {
		System.out.println("覆盖SimpleHostRoutingFilter");
		Map<String, Object> info = this.helper.debug(verb, uri, headers, params,
				requestEntity);
		URL host = RequestContext.getCurrentContext().getRouteHost();
		HttpHost httpHost = getHttpHost(host);
		//TODO 不拆分地址
//		uri = StringUtils.cleanPath(
//				MULTIPLE_SLASH_PATTERN.matcher(host.getPath() + uri).replaceAll("/"));
		long contentLength = getContentLength(request);

		ContentType contentType = null;

		if (request.getContentType() != null) {
			contentType = ContentType.parse(request.getContentType());
		}

		InputStreamEntity entity = new InputStreamEntity(requestEntity, contentLength,
				contentType);
		uri = UriUtils.decode(uri, characterEncoding(request));
		HttpRequest httpRequest = buildHttpRequest(verb, uri, entity, headers, params,
				request);
		try {
			log.debug(httpHost.getHostName() + " " + httpHost.getPort() + " "
					+ httpHost.getSchemeName());
			CloseableHttpResponse zuulResponse = forwardRequest(httpclient, httpHost,
					httpRequest);
			this.helper.appendDebug(info, zuulResponse.getStatusLine().getStatusCode(),
					revertHeaders(zuulResponse.getAllHeaders()));
			return zuulResponse;
		}
		finally {
			// When HttpClient instance is no longer needed,
			// shut down the connection manager to ensure
			// immediate deallocation of all system resources
			// httpclient.getConnectionManager().shutdown();
		}
	}

	private CloseableHttpResponse forwardRequest(CloseableHttpClient httpclient,
			HttpHost httpHost, HttpRequest httpRequest) throws IOException {
		return httpclient.execute(httpHost, httpRequest);
	}
	private String characterEncoding(HttpServletRequest request) {
		return request.getCharacterEncoding() != null ? request.getCharacterEncoding()
				: WebUtils.DEFAULT_CHARACTER_ENCODING;
	}
	private HttpHost getHttpHost(URL host) {
		HttpHost httpHost = new HttpHost(host.getHost(), host.getPort(),
				host.getProtocol());
		return httpHost;
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值