Spring Netflix Zuul:API-Gateway - 转换 JSON 请求
Posted
技术标签:
【中文标题】Spring Netflix Zuul:API-Gateway - 转换 JSON 请求【英文标题】:Spring Netflix Zuul: API-Gateway - Transforming a JSON request 【发布时间】:2018-06-22 03:24:37 【问题描述】:我目前正在使用 Spring Netflix Zuul 库为新的微服务系统构建 API 网关。
到目前为止,我的网关包含PRE
和POST
过滤器,它们拦截请求并执行所需的逻辑等。
我看到的一件事是,对特定微服务的 REST 调用需要调用一个 API 端点(GET 或 POST),其中包含非常复杂的 JSON 有效负载数据。
对于向包含此 JSON 的微服务发送请求的最终用户而言,用户将不友好。
我有一个想法,让 API 网关充当中介,用户可以向 API 网关提交更“简化/用户友好”的 JSON,API 网关将使用正确的“复杂”JSON 转换 JSON 有效负载目标微服务可以理解的结构,以便有效地处理请求。
我对 Netflix Zuul 的理解是,这可以通过创建 RouteFilter
然后在此处包含此逻辑来完成。
谁能解释这种转变是否(或如何)可以使用 Netflix Zuul 完成?
感谢任何建议。
谢谢。
【问题讨论】:
【参考方案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% 准确,因为我正在研究它,但这是一个开始。
【讨论】:
这与我最近提出的问题大致相同 (***.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;
【讨论】:
以上是关于Spring Netflix Zuul:API-Gateway - 转换 JSON 请求的主要内容,如果未能解决你的问题,请参考以下文章
Zuul spring cloud zuul com.netflix.zuul.exception.ZuulException GENERAL解决方案
在 Spring Boot 中使用 netflix zuul 面临微服务问题
Spring Cloud Eureka Netflix zuul 过滤器
Netflix Zuul注解导致spring boot app启动失败