【问题标题】:Spring Netflix Zuul: API-Gateway - Transforming a JSON requestSpring Netflix Zuul:API-Gateway - 转换 JSON 请求
【发布时间】:2018-06-22 03:24:37
【问题描述】:

我目前正在使用 Spring Netflix Zuul 库为新的微服务系统构建 API 网关。

到目前为止,我的网关包含PREPOST 过滤器,它们拦截请求并执行所需的逻辑等。

我看到的一件事是,对特定微服务的 REST 调用需要调用一个 API 端点(GET 或 POST),其中包含非常复杂的 JSON 有效负载数据。

对于向包含此 JSON 的微服务发送请求的最终用户而言,用户将不友好。

我有一个想法,让 API 网关充当中介,用户可以向 API 网关提交更“简化/用户友好”的 JSON,API 网关将使用正确的“复杂”JSON 转换 JSON 有效负载目标微服务可以理解的结构,以便有效地处理请求。

我对 Netflix Zuul 的理解是,这可以通过创建 RouteFilter 然后在此处包含此逻辑来完成。

谁能解释这种转变是否(或如何)可以使用 Netflix Zuul 完成?

感谢任何建议。

谢谢。

【问题讨论】:

    标签: json api spring-boot netflix-zuul api-gateway


    【解决方案1】:

    毫无疑问,您可以使用 Zuul 做到这一点,我目前正在尝试做几乎相同的事情。我建议你看看这个 repo:

    sample-zuul-filters

    还有 github 上的 official doc

    过滤器必须扩展 ZuulFilter 并实现以下方法:

    /** 
     *return a string defining when your filter must execute during zuul's
     *lyfecyle ('pre'/'post' routing 
     **/
    @Override
    public String filterType(){
    
       return 'pre';  // run this filter before sending the final request
    }
    
    /** 
     * return an int describing the order that the filter should run on,  
     *  (relative to the other filters and the current 'pre' or 'post' context)
     **/
    @Override
    public int filterOrder {
        return 1; //this filter runs first in a pre-request context
    }
    
    /** 
     * return a boolean indicating if the filter should run or not
     **/
    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
    
        if(ctx.getRequest().getRequestURI().equals("/theRouteIWantToFilter"))
        {
            return true;
        }
        else {
            return false;
        }
    }
    
    /**
     * After all the config stuffs you can set what your filter actually does 
     * here. This is where your json logic goes. 
     */
    @Override
    public Object run() {
        try {
         RequestContext ctx = RequestContext.getCurrentContext();
         HttpServletRequest request = ctx.getRequest();
         InputStream stream = ctx.getResponseDataStream();
         String body = StreamUtils.copyToString(stream, Charset.forName("UTF-8"));
    
         // transform your json and send it to the api. 
    
         ctx.setResponseBody(" Modified body :  " + body);
        } catch (IOException e) {
            e.printStackTrace();
        }
         return null; 
    }
    

    我不确定我的答案是否 100% 准确,因为我正在研究它,但这是一个开始。

    【讨论】:

    • 这与我最近提出的问题大致相同 (stackoverflow.com/questions/64586116/…),其中我提到了 netflix zuul。我几乎采用了相同的方法来回答这个问题。我唯一担心的是适配器实现会有点复杂(例如,产品中会有很多 POST 服务,识别当前正在处理的 POST 有点棘手)。
    【解决方案2】:

    我已经在预过滤器中完成了有效负载转换,但这也应该在路由过滤器中工作。在将请求转发到目标微服务之前,使用 com.netflix.zuul.http.HttpServletRequestWrapper 捕获和修改原始请求负载。

    示例代码:

    package com.sample.zuul.filters.pre;
    
    import com.google.common.io.CharStreams;
    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    import com.netflix.zuul.http.HttpServletRequestWrapper;
    import com.netflix.zuul.http.ServletInputStreamWrapper;
    import org.json.simple.JSONObject;
    import org.json.simple.parser.JSONParser;
    import org.json.simple.parser.ParseException;
    
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    public class JsonConverterFilter extends ZuulFilter {
    
        @Override
        public String filterType() {
            return "pre";
        }
    
        @Override
        public int filterOrder() {
            return 0; //  Set it to whatever the order of your filter is
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() {
    
            RequestContext context = RequestContext.getCurrentContext();
            HttpServletRequest request = new HttpServletRequestWrapper(context.getRequest());
    
            String requestData = null;
            JSONParser jsonParser = new JSONParser();
            JSONObject requestJson = null;
    
            try {
                if (request.getContentLength() > 0) {
                    requestData = CharStreams.toString(request.getReader());
                }
                if (requestData == null) {
                    return null;
                }
                requestJson = (JSONObject) jsonParser.parse(requestData);
            } catch (Exception e) {
                //Add your exception handling code here
            }
    
            JSONObject modifiedRequest = modifyJSONRequest(requestJson);
    
            final byte[] newRequestDataBytes = modifiedRequest.toJSONString().getBytes();
    
            request = getUpdatedHttpServletRequest(request, newRequestDataBytes);
            context.setRequest(request);
            return null;
        }
    
    
    
        private JSONObject modifyJSONRequest(JSONObject requestJSON) {
    
            JSONObject jsonObjectDecryptedPayload = null;
            try {
                jsonObjectDecryptedPayload = (JSONObject) new JSONParser()
                        .parse("Your new complex json");
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return jsonObjectDecryptedPayload;
        }
    
    
        private HttpServletRequest getUpdatedHttpServletRequest(HttpServletRequest request, final byte[] newRequestDataBytes) {
            request = new javax.servlet.http.HttpServletRequestWrapper(request) {
    
                @Override
                public BufferedReader getReader() throws IOException {
                    return new BufferedReader(
                            new InputStreamReader(new ByteArrayInputStream(newRequestDataBytes)));
                }
    
                @Override
                public ServletInputStream getInputStream() throws IOException {
                    return new ServletInputStreamWrapper(newRequestDataBytes);
                }
             /*
                 * Forcing any calls to HttpServletRequest.getContentLength to return the accurate length of bytes
                 * from a modified request
                 */
                @Override
                public int getContentLength() {
                    return newRequestDataBytes.length;
                }
            };
            return request;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-19
      • 1970-01-01
      • 2014-04-26
      • 1970-01-01
      • 2020-01-14
      • 2020-04-30
      • 2020-03-28
      • 1970-01-01
      相关资源
      最近更新 更多