SpringCloud 自定義Zuul過(guò)濾器示例

2023-11-23 14:06 更新

下面的大多數(shù)“如何編寫(xiě)”示例都包含在示例Zuul過(guò)濾器項(xiàng)目中。在該存儲(chǔ)庫(kù)中也有一些處理請(qǐng)求或響應(yīng)正文的示例。

如何編寫(xiě)前置過(guò)濾器

前置過(guò)濾器可在RequestContext中設(shè)置數(shù)據(jù),以便在下游的過(guò)濾器中使用。主要用例是設(shè)置路由過(guò)濾器所需的信息。以下示例顯示了Zuul前置過(guò)濾器:

public class QueryParamPreFilter extends ZuulFilter {
	@Override
	public int filterOrder() {
		return PRE_DECORATION_FILTER_ORDER - 1; // run before PreDecoration
	}

	@Override
	public String filterType() {
		return PRE_TYPE;
	}

	@Override
	public boolean shouldFilter() {
		RequestContext ctx = RequestContext.getCurrentContext();
		return !ctx.containsKey(FORWARD_TO_KEY) // a filter has already forwarded
				&& !ctx.containsKey(SERVICE_ID_KEY); // a filter has already determined serviceId
	}
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		if (request.getParameter("sample") != null) {
		    // put the serviceId in `RequestContext`
    		ctx.put(SERVICE_ID_KEY, request.getParameter("foo"));
    	}
        return null;
    }
}

前面的過(guò)濾器從sample請(qǐng)求參數(shù)中填充SERVICE_ID_KEY實(shí)際上,您不應(yīng)該執(zhí)行這種直接映射。而是應(yīng)從sample的值中查找服務(wù)ID。

現(xiàn)在已填充SERVICE_ID_KEY,PreDecorationFilter將不運(yùn)行,而RibbonRoutingFilter將運(yùn)行。

 如果要路由到完整URL,請(qǐng)致電ctx.setRouteHost(url)。

要修改路由過(guò)濾器轉(zhuǎn)發(fā)到的路徑,請(qǐng)?jiān)O(shè)置REQUEST_URI_KEY。

如何編寫(xiě)路由過(guò)濾器

路由過(guò)濾器在預(yù)過(guò)濾器之后運(yùn)行,并向其他服務(wù)發(fā)出請(qǐng)求。這里的許多工作是將請(qǐng)求和響應(yīng)數(shù)據(jù)與客戶(hù)端所需的模型相互轉(zhuǎn)換。以下示例顯示了Zuul路由過(guò)濾器:

public class OkHttpRoutingFilter extends ZuulFilter {
	@Autowired
	private ProxyRequestHelper helper;

	@Override
	public String filterType() {
		return ROUTE_TYPE;
	}

	@Override
	public int filterOrder() {
		return SIMPLE_HOST_ROUTING_FILTER_ORDER - 1;
	}

	@Override
	public boolean shouldFilter() {
		return RequestContext.getCurrentContext().getRouteHost() != null
				&& RequestContext.getCurrentContext().sendZuulResponse();
	}

    @Override
    public Object run() {
		OkHttpClient httpClient = new OkHttpClient.Builder()
				// customize
				.build();

		RequestContext context = RequestContext.getCurrentContext();
		HttpServletRequest request = context.getRequest();

		String method = request.getMethod();

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

		Headers.Builder headers = new Headers.Builder();
		Enumeration<String> headerNames = request.getHeaderNames();
		while (headerNames.hasMoreElements()) {
			String name = headerNames.nextElement();
			Enumeration<String> values = request.getHeaders(name);

			while (values.hasMoreElements()) {
				String value = values.nextElement();
				headers.add(name, value);
			}
		}

		InputStream inputStream = request.getInputStream();

		RequestBody requestBody = null;
		if (inputStream != null && HttpMethod.permitsRequestBody(method)) {
			MediaType mediaType = null;
			if (headers.get("Content-Type") != null) {
				mediaType = MediaType.parse(headers.get("Content-Type"));
			}
			requestBody = RequestBody.create(mediaType, StreamUtils.copyToByteArray(inputStream));
		}

		Request.Builder builder = new Request.Builder()
				.headers(headers.build())
				.url(uri)
				.method(method, requestBody);

		Response response = httpClient.newCall(builder.build()).execute();

		LinkedMultiValueMap<String, String> responseHeaders = new LinkedMultiValueMap<>();

		for (Map.Entry<String, List<String>> entry : response.headers().toMultimap().entrySet()) {
			responseHeaders.put(entry.getKey(), entry.getValue());
		}

		this.helper.setResponse(response.code(), response.body().byteStream(),
				responseHeaders);
		context.setRouteHost(null); // prevent SimpleHostRoutingFilter from running
		return null;
    }
}

前面的過(guò)濾器將Servlet請(qǐng)求信息轉(zhuǎn)換為OkHttp3請(qǐng)求信息,執(zhí)行HTTP請(qǐng)求,并將OkHttp3響應(yīng)信息轉(zhuǎn)換為Servlet響應(yīng)。

如何編寫(xiě)帖子過(guò)濾器

后置過(guò)濾器通常操縱響應(yīng)。以下過(guò)濾器將隨機(jī)UUID添加為X-Sample標(biāo)頭:

public class AddResponseHeaderFilter extends ZuulFilter {
	@Override
	public String filterType() {
		return POST_TYPE;
	}

	@Override
	public int filterOrder() {
		return SEND_RESPONSE_FILTER_ORDER - 1;
	}

	@Override
	public boolean shouldFilter() {
		return true;
	}

	@Override
	public Object run() {
		RequestContext context = RequestContext.getCurrentContext();
    	HttpServletResponse servletResponse = context.getResponse();
		servletResponse.addHeader("X-Sample", UUID.randomUUID().toString());
		return null;
	}
}

 其他操作,例如轉(zhuǎn)換響應(yīng)主體,則更加復(fù)雜且計(jì)算量大。

以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)