微服务中 Zuul 服务网关一共定义了四种类型的过滤器:
pre: 在请求被路由 (转发) 之前调用
route: 在路由 (请求) 转发时被调用
error: 服务网关发生异常时被调用
post: 在路由 (转发) 请求后调用
我在项目中用到了, pre/error/post 三种类型, 先记录一下
pre 过滤器主要是用来校验各种信息的
- import com.alibaba.fastjson.JSONObject;
- import com.dkjk.gateway.context.ResponseBean;
- import com.dkjk.gateway.domain.DockCompanyService;
- import com.dkjk.gateway.domain.UserService;
- import com.netflix.zuul.ZuulFilter;
- import com.netflix.zuul.context.RequestContext;
- import com.netflix.zuul.exception.ZuulException;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.stereotype.Component;
- import org.springframework.web.bind.annotation.RequestMethod;
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.io.PrintWriter;
- /**
- * @author: qjc
- * @createTime: 2019/4/13 16:08
- * @Description: 接口安全验证过滤器
- */
- @Component
- @Slf4j
- public class ValidFilter extends ZuulFilter {
- @Override
- public String filterType() {
- return "pre";
- }
- @Override
- public int filterOrder() {
- return 0;
- }
- @Override
- public boolean shouldFilter() {
- // 进行跨域请求的时候, 并且请求头中有额外参数, 比如 token, 客户端会先发送一个 OPTIONS 请求来探测后续需要发起的跨域 POST 请求是否安全可接受
- // 所以这个请求就不需要拦截, 下面是处理方式
- RequestContext requestContext = RequestContext.getCurrentContext();
- HttpServletRequest request = requestContext.getRequest();
- if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
- log.info("OPTIONS 请求不做拦截操作");
- return false;
- }
- return true;
- }
- @Override
- public Object run() throws ZuulException {
- RequestContext requestContext = RequestContext.getCurrentContext();
- HttpServletRequest request = requestContext.getRequest();
- String userToken = request.getHeader("apikey");
- if (StringUtils.isBlank(userToken)) {
- log.warn("apikey 为空");
- sendError(requestContext, 99001, "请传输参数 apikey");
- return null;
- }
- return null;
- }
- /**
- * 发送错误消息
- *
- * @param requestContext
- * @param status
- * @param msg
- */
- private void sendError(RequestContext requestContext, int status, String msg) {
- // 过滤该请求, 不往下级服务转发, 到此结束不进行路由
- requestContext.setSendZuulResponse(false);
- HttpServletResponse response = requestContext.getResponse();
- response.setHeader("Content-type", "application/json;charset=UTF-8");
- response.setCharacterEncoding("UTF-8");
- PrintWriter pw = null;
- try {
- pw = response.getWriter();
- pw.write(JSONObject.toJSONString(new ResponseBean(status, msg, null)));
- } catch (IOException e) {
- log.error(e.getMessage());
- } finally {
- pw.close();
- }
- }
- }
post 过滤器可以在请求转发后获取请求信息和响应入库, 或者日志记录
- import com.alibaba.fastjson.JSON;
- import com.netflix.zuul.ZuulFilter;
- import com.netflix.zuul.context.RequestContext;
- import com.netflix.zuul.exception.ZuulException;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.io.IOUtils;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.stereotype.Component;
- import org.springframework.Web.bind.annotation.RequestMethod;
- import javax.servlet.http.HttpServletRequest;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Enumeration;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * @author: qjc
- * @createTime: 2019/5/6 11:07
- * @Description:
- */
- @Component
- @Slf4j
- public class ResponseFilter extends ZuulFilter {
- @Override
- public String filterType() {
- return "post";
- }
- @Override
- public int filterOrder() {
- return 2;
- }
- @Override
- public boolean shouldFilter() {
- // 进行跨域请求的时候, 并且请求头中有额外参数, 比如 token, 客户端会先发送一个 OPTIONS 请求来探测后续需要发起的跨域 POST 请求是否安全可接受
- // 所以这个请求就不需要拦截, 下面是处理方式
- RequestContext requestContext = RequestContext.getCurrentContext();
- HttpServletRequest request = requestContext.getRequest();
- if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
- log.info("OPTIONS 请求不做拦截操作");
- return false;
- }
- // 如果前面的拦截器不进行路由, 那么后面的过滤器就没必要执行
- if (!requestContext.sendZuulResponse()) {
- return false;
- }
- return true;
- }
- @Override
- public Object run() throws ZuulException {
- RequestContext requestContext = RequestContext.getCurrentContext();
- InputStream stream = requestContext.getResponseDataStream();
- if (stream == null) {
- return null;
- }
- HttpServletRequest request = requestContext.getRequest();
- String requestParams = getRequestParams(requestContext, request);
- System.err.println(requestParams);
- try {
- String responseBoby = IOUtils.toString(stream);
- RequestContext.getCurrentContext().setResponseBody(responseBoby);
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
- // 获取请求参数, 适用于 POST 请求 / GET 请求, 以及参数拼接在 URL 后面的 POST 请求
- private String getRequestParams(RequestContext requestContext, HttpServletRequest request) {
- String requestParams = null;
- String requestMethod = request.getMethod();
- StringBuilder params = new StringBuilder();
- Enumeration<String> names = request.getParameterNames();
- if (requestMethod.equals("GET")) {
- while (names.hasMoreElements()) {
- String name = (String) names.nextElement();
- params.append(name);
- params.append("=");
- params.append(request.getParameter(name));
- params.append("&");
- }
- requestParams = params.delete(params.length() - 1, params.length()).toString();
- } else {
- Map<String, String> res = new HashMap<>();
- Enumeration<?> temp = request.getParameterNames();
- if (null != temp) {
- while (temp.hasMoreElements()) {
- String en = (String) temp.nextElement();
- String value = request.getParameter(en);
- res.put(en, value);
- }
- requestParams = JSON.toJSONString(res);
- }
- if (StringUtils.isBlank(requestParams) || "{}".equals(requestParams)) {
- BufferedReader br = null;
- StringBuilder sb = new StringBuilder("");
- try {
- br = request.getReader();
- String str;
- while ((str = br.readLine()) != null) {
- sb.append(str);
- }
- br.close();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (null != br) {
- try {
- br.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- requestParams = sb.toString();
- }
- }
- return requestParams;
- }
- }
error 过滤器是在服务网关出现异常的时候起作用的
- import com.alibaba.fastjson.JSONObject;
- import com.dkjk.gateway.context.ResponseBean;
- import com.netflix.zuul.ZuulFilter;
- import com.netflix.zuul.context.RequestContext;
- import com.netflix.zuul.exception.ZuulException;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Component;
- import org.springframework.util.ReflectionUtils;
- import javax.servlet.http.HttpServletResponse;
- import java.io.PrintWriter;
- /**
- * @author: qjc
- * @createTime: 2019/5/30 19:11
- * @Description: 处理请求发生错误时过滤器
- */
- @Component
- @Slf4j
- public class ErrorFilter extends ZuulFilter {
- @Override
- public String filterType() {
- return "error";
- }
- @Override
- public int filterOrder() {
- // 需要在默认的 SendErrorFilter 之前
- return -1;
- }
- @Override
- public boolean shouldFilter() {
- // 只有在抛出异常时才会进行拦截
- return RequestContext.getCurrentContext().containsKey("throwable");
- }
- @Override
- public Object run() {
- try {
- RequestContext requestContext = RequestContext.getCurrentContext();
- Object e = requestContext.get("throwable");
- if (e != null && e instanceof ZuulException) {
- ZuulException zuulException = (ZuulException) e;
- // 删除该异常信息, 不然在下一个过滤器中还会被执行处理
- requestContext.remove("throwable");
- // 响应给客户端信息
- HttpServletResponse response = requestContext.getResponse();
- response.setHeader("Content-type", "application/json;charset=UTF-8");
- response.setCharacterEncoding("UTF-8");
- PrintWriter pw = null;
- pw = response.getWriter();
- pw.write(JSONObject.toJSONString(new ResponseBean(99999, "系统出现异常", null)));
- pw.close();
- }
- } catch (Exception ex) {
- log.error("Exception filtering in custom error filter", ex);
- ReflectionUtils.rethrowRuntimeException(ex);
- }
- return null;
- }
- }
服务网关 ZuulFilter 过滤器 --pre/post/error 的用法(校验和获取路由后的请求 / 响应信息, 处理服务网关异常)
来源: http://www.bubuko.com/infodetail-3077786.html