如何在 Zuul 后置过滤器中拦截和编辑响应正文?

Posted

技术标签:

【中文标题】如何在 Zuul 后置过滤器中拦截和编辑响应正文?【英文标题】:How to intercept and edit response body in Zuul post filter? 【发布时间】:2019-11-06 01:48:00 【问题描述】:

我正在使用 Zuul 后置过滤器来拦截响应。我的要求是在响应 json 中添加一个新字段。我能够拦截响应并对其进行编辑。但是,无法将更新的响应设置为 RequestContext。如何在使用 Zuul 作为后置过滤器中的代理时读取响应正文、编辑并将其更新回 RequestContext?

请找到我正在使用的以下代码。

private void updateResponseBody(RequestContext ctx) throws IOException, JSONException 

    final InputStream responseDataStream = ctx.getResponseDataStream();
    String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8"));
    JSONObject jsonObj = new JSONObject(responseData);
    JSONArray groupsArray = jsonObj.getJSONArray("list");
    for (int i = 0; i < groupsArray.length(); i++) 
        JSONObject groupId = groupsArray.getJSONObject(i);
        groupId.accumulate("new_json_field_name", "new_json_field_value");
    
    String updatedResponse = jsonObj.toString();
    // ctx.setResponseBody(body); // also not working
    ctx.setResponseDataStream(org.apache.commons.io.IOUtils.toInputStream(updatedResponse, "UTF-8"));


我得到的错误是:

Error while sending response to client: java.io.IOException: An existing connection was forcibly closed by the remote host.

谁能帮我解决这个问题。

【问题讨论】:

【参考方案1】:

我遇到了同样的错误,并且疯狂地修改How to get response body in Zuul post filter? 中描述的代码尝试不同的可能性。最后我通过在servletResponse.getOutputStream()而不是ctx.setResponseDataStream()OutputStream中写下答案,在this post中找到了解决方案:

HttpServletResponse servletResponse = ctx.getResponse();

  ...

String updatedResponse = jsonObj.toString();
try 
    OutputStream outStream = servletResponse.getOutputStream();
    outStream.write(updatedResponse.getBytes(), 0, updatedResponse.length());
    outStream.flush();
    outStream.close();
 catch (IOException e) 
    log.warn("Error reading body", e);


【讨论】:

【参考方案2】:

我有一个类似的任务,并尝试通过写入 OutputStream 来完成。这有效,但有一个奇怪的副作用,它使响应中的 HttpHeaders 被删除或损坏。这使得调用在生产中产生 CORS 错误,即使它通过 Postman 在本地运行良好。

我编写了以下方法,我从 Post Zuul 过滤器的 run() 方法中调用该方法,以将单个节点/值添加到返回 Json。

    private void addJsonNode(RequestContext requestContext,String name, String id) 
        HttpServletResponse servletResponse = requestContext.getResponse();
        try 
            final InputStream responseDataStream = requestContext.getResponseDataStream();
            String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8"));
            JSONObject jsonObject = new JSONObject(responseData);
            jsonObject.put(name, id);
            String updatedResponse = jsonObject.toString(4);
            requestContext.setResponseBody(updatedResponse);
         catch (IOException e) 
            log.warn("Error reading body", e);
         catch (JSONException e) 
            log.warn("Error reading body", e);
        
    

【讨论】:

以上是关于如何在 Zuul 后置过滤器中拦截和编辑响应正文?的主要内容,如果未能解决你的问题,请参考以下文章

sprignclou的zuul的实战

在zuul过滤器中修改请求正文无法正常工作

zuul实现模块异常统一拦截返回

(34)java Spring Cloud+Spring boot+mybatis企业快速开发架构之SpringCloud-Zuul过滤器介绍及使用(传递数据拦截请求和异常处理)

Zuul 网关

如何使用保留请求正文和响应正文的 servlet 过滤器记录请求和响应?