如何使用zuul过滤器转换客户端请求主体?

时间:2017-01-27 14:59:13

标签: java spring netflix-zuul

我想使用Zuul对来自客户端的请求进行身份验证,转换和转发到内部服务。目标是从客户端隐藏遗留API。

我的想法是:客户端将具有对象A的JSON表示的POST请求发送到嵌入了Zuul的API网关。 API网关将正文从A转换为LegacyA并将其发送到内部服务。

例如,我搜索了一种转换以下JSON的方法:

["hello","world"]

在这个JSON中:

{hashCode("hello"):"hello", hashCode("world"):"world")}

我想使用预过滤器。但是我有问题要重写一个有效的请求。

你知道我该怎么办?

我写过这个过滤器:

public class RestZuulFilter extends ZuulFilter {

    private final ObjectMapper objectMapper;

    @Autowired
    public RestZuulFilter(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 100;
    }

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

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();

        HttpServletRequestWrapper wrapper = new MyWrapper(ctx.getRequest());
        ctx.setRequest(wrapper);

        return null;
    }

    class MyWrapper extends HttpServletRequestWrapper {

        /**
         * Constructs a request object wrapping the given request.
         *
         * @param request The request to wrap
         * @throws IllegalArgumentException if the request is null
         */
        public MyWrapper(HttpServletRequest request) {
            super(request);
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            ServletInputStream inputStream = this.getRequest().getInputStream();

            List<String> test = objectMapper.readValue(inputStream, new TypeReference<List<String>>() {
            });
            Map<Integer, String> result = test.stream()
                    .collect(Collectors.toMap(String::hashCode, str -> str));

            byte[] json = objectMapper.writeValueAsBytes(result);
            ServletInputStream response = new ServletInputStreamWrapper(json);

            return response;
        }
    }
}

我遇到的问题是内容长度没有按顺序更新。

2 个答案:

答案 0 :(得分:3)

看一下正在转换的请求体的以下示例。我认为这对你有用。

    InputStream in = (InputStream) context.get("requestEntity");
    if (in == null) {
        in = context.getRequest().getInputStream();
    }
    String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
    body = body.toUpperCase();
    context.set("requestEntity", new ByteArrayInputStream(body.getBytes("UTF-8")));

完整的课程:

https://github.com/spring-cloud-samples/sample-zuul-filters/blob/master/src/main/java/org/springframework/cloud/samplezuulfilters/UppercaseRequestEntityFilter.java

答案 1 :(得分:0)

最快的方法是在过滤器中使用 HttpServletRequestWrapper 类

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import static com.netflix.zuul.context.RequestContext.getCurrentContext;

public class ModifyBodyFilter extends ZuulFilter {

@Override
public String filterType() {
    return "pre";
}

@Override
public int filterOrder() {
    return 0;
}

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

@Override
public Object run() {

    RequestContext ctx = getCurrentContext();

    String newBody = "{\"key\":\"value\"}";
    byte[] bytes = newBody.getBytes();

    ctx.setRequest(new HttpServletRequestWrapper(getCurrentContext().getRequest()) {
        @Override
        public ServletInputStream getInputStream() throws IOException {
            return new ServletInputStreamWrapper(bytes);
        }

        @Override
        public int getContentLength() {
            return bytes.length;
        }

        @Override
        public long getContentLengthLong() {
            return bytes.length;
        }
    });

    return null;
}

}