当前位置: 首页 > 知识库问答 >
问题:

限制基于 CXF JAX-RS 的服务中的输出有效负载响应

农飞星
2023-03-14

我有多个使用cxf/spring构建的jax-rs服务。我想控制所有服务的输出负载响应大小。为了简单起见,假设任何服务中的api都不应该返回超过500个字符的JSON响应有效负载,我希望在一个地方控制这一点,而不是依赖单个服务来遵守这一要求。(我们已经在所有服务所依赖的定制框架/基础组件中内置了其他功能)。

我已经尝试使用JAX-RS的< code>WriterInterceptor 、< code > ContainerResponseFilter 和CXF的< code>Phase Interceptor来实现这一点,但是这些方法似乎都不能完全满足我的要求。更多关于我目前所做的细节:

选项 1:(WriterInteceptor)在重写的方法中,我获取输出流并将缓存的最大大小设置为 500。当我调用在响应负载中返回超过 500 个字符的 api 时,我得到一个 HTTP 400 错误请求状态,但响应正文包含整个 JSON 有效负载。

@Provider
public class ResponsePayloadInterceptor implements WriterInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(ResponsePayloadInterceptor.class);

    @Override
    public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
        final OutputStream outputStream = context.getOutputStream();

        CacheAndWriteOutputStream cacheAndWriteOutputStream = new CacheAndWriteOutputStream(outputStream);
        cacheAndWriteOutputStream.setMaxSize(500);
        context.setOutputStream(cacheAndWriteOutputStream);

        context.proceed();
    }
}

选项2a:(CXF相位Inteceptor)在覆盖的方法中,我从ouputstream中获取作为String的响应并检查它的大小,如果大于500,我创建一个新的响应对象,其中只有数据太多的数据并在消息中设置它。即使响应是

@Provider
public class ResponsePayloadInterceptor extends AbstractPhaseInterceptor<Message> {
    private static final Logger LOGGER = LoggerFactory.getLogger(ResponsePayloadInterceptor.class);

    public ResponsePayloadInterceptor() {
        super(Phase.POST_MARSHAL);
    }

    @Override
    public void handleMessage(Message message) throws Fault {
        LOGGER.info("handleMessage() - Response intercepted");
        try {
            OutputStream outputStream = message.getContent(OutputStream.class);
...
            CachedOutputStream cachedOutputStream = (CachedOutputStream) outputStream;
            String responseBody = IOUtils.toString(cachedOutputStream.getInputStream(), "UTF-8");
...
            LOGGER.info("handleMessage() - Response: {}", responseBody);
            LOGGER.info("handleMessage() - Response Length: {}", responseBody.length());
            if (responseBody.length() > 500) {
                Response response = Response.status(Response.Status.BAD_REQUEST)
                                            .entity("Too much data").build();
                message.getExchange().put(Response.class, response);
            }
        } catch (IOException e) {
            LOGGER.error("handleMessage() - Error");
            e.printStackTrace();
        }
    }
}

选项2b:(CXF相位接收器)与上述相同,但仅更改if块的内容。若响应长度大于500,我将创建一个新的输出流,其中包含字符串“太多数据”,并在消息中设置它。但是如果响应有效载荷为

        if (responseBody.length() > 500) {
            InputStream inputStream = new ByteArrayInputStream("Too much data".getBytes("UTF-8"));
            outputStream.flush();
            IOUtils.copy(inputStream, outputStream);

            OutputStream out = new CachedOutputStream();
            out.write("Too much data".getBytes("UTF-8"));
            message.setContent(OutputStream.class, out);
        }

选项 3:(ContainerResponseFilter)使用 ContainerResponseFilter,我添加了一个值为 500 的内容长度响应标头。如果响应长度为

@Provider
public class ResponsePayloadFilter implements ContainerResponseFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(ResponsePayloadFilter.class);

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        LOGGER.info("filter() - Response intercepted");
        CachedOutputStream cos = (CachedOutputStream) responseContext.getEntityStream();
        StringBuilder responsePayload = new StringBuilder();
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        if (cos.getInputStream().available() > 0) {
            IOUtils.copy(cos.getInputStream(), out);
            byte[] responseEntity = out.toByteArray();
            responsePayload.append(new String(responseEntity));
        }

        LOGGER.info("filter() - Content: {}", responsePayload.toString());
        responseContext.getHeaders().add("Content-Length", "500");
    }
}

关于如何调整上述方法以获得我想要的或任何其他不同指针的建议?

共有1个答案

秦安宁
2023-03-14

我使用这个答案的帮助部分解决了这个问题。我说部分原因是因为我能够成功控制有效负载,但不是响应状态代码。理想情况下,如果响应长度大于 500 并且我修改了消息内容,则我想发送不同的响应状态代码(200 OK 除外)。但是,对于我来说,这是一个足够好的解决方案,可以在这一点上继续进行。如果我弄清楚如何更新状态代码,我会回来更新这个答案。

import org.apache.commons.io.IOUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class ResponsePayloadInterceptor extends AbstractPhaseInterceptor<Message> {
    private static final Logger LOGGER = LoggerFactory.getLogger(ResponsePayloadInterceptor.class);

    public ResponsePayloadInterceptor() {
        super(Phase.PRE_STREAM);
    }

    @Override
    public void handleMessage(Message message) throws Fault {
        LOGGER.info("handleMessage() - Response intercepted");
        try {
            OutputStream outputStream = message.getContent(OutputStream.class);
            CachedOutputStream cachedOutputStream = new CachedOutputStream();
            message.setContent(OutputStream.class, cachedOutputStream);

            message.getInterceptorChain().doIntercept(message);

            cachedOutputStream.flush();
            cachedOutputStream.close();

            CachedOutputStream newCachedOutputStream = (CachedOutputStream) message.getContent(OutputStream.class);
            String currentResponse = IOUtils.toString(newCachedOutputStream.getInputStream(), "UTF-8");
            newCachedOutputStream.flush();
            newCachedOutputStream.close();

            if (currentResponse != null) {
                LOGGER.info("handleMessage() - Response: {}", currentResponse);
                LOGGER.info("handleMessage() - Response Length: {}", currentResponse.length());

                if (currentResponse.length() > 500) {
                    InputStream replaceInputStream = IOUtils.toInputStream("{\"message\":\"Too much data\"}", "UTF-8");

                    IOUtils.copy(replaceInputStream, outputStream);
                    replaceInputStream.close();

                    message.setContent(OutputStream.class, outputStream);
                    outputStream.flush();
                    outputStream.close();
                } else {
                    InputStream replaceInputStream = IOUtils.toInputStream(currentResponse, "UTF-8");

                    IOUtils.copy(replaceInputStream, outputStream);
                    replaceInputStream.close();

                    message.setContent(OutputStream.class, outputStream);
                    outputStream.flush();
                    outputStream.close();
                }
            }
        } catch (IOException e) {
            LOGGER.error("handleMessage() - Error", e);
            throw new RuntimeException(e);
        }
    }
 类似资料:
  • 我想在RESTful API中支持分页。 我的API方法应该通过返回产品的JSON列表。但是,可能有成千上万的产品,我想浏览它们,所以我的请求应该如下所示: 但我的JSON响应需要是什么样的呢?API使用者通常会在响应中期望分页元数据吗?还是只需要一系列产品?为什么? 看起来Twitter的API包含元数据:https://dev.twitter.com/docs/api/1/get/lists/

  • 在实现基于事件源的微服务时,我们遇到的主要问题之一是聚合响应数据。例如,我们可能有两个实体,如学校和学生。一个微服务可能负责处理学校相关的业务逻辑,而另一个微服务可能处理学生。 现在,如果有人通过RESTendpoint进行查询并询问某个特定的学生,他们可能希望了解学校和学生的详细信息,那么对我来说,唯一已知的方法是以下方法。 > 使用类似于服务链接的东西。一个例子是Api-Gateway在向几个

  • 本文向大家介绍详解基于Centos7+Nginx+Tomcat8的负载均衡服务器的搭建,包括了详解基于Centos7+Nginx+Tomcat8的负载均衡服务器的搭建的使用技巧和注意事项,需要的朋友参考一下 由于工作的需求,在使用中,需要搭建负载均衡,研究了Apache+Tomat负载均衡的方案,并且通过检索相关的文章,进行了比较发现,Apache负载负载均衡在使用的效率上,远远不如Nginx的效

  • Gzip 我尝试切换到二进制操作码,认为可能压缩文本=binary,但这不起作用。我真的看不出我做错了什么或者错过了什么。此实现不包括跨越消息的滑动压缩窗口。我想响应头说明了这一点。帮助感激地接受了。

  • 我有一个要求,其中,作为Web服务[Java]的一部分,我将作业的详细信息输入数据库,数据库由Windows服务[C#]异步处理,并对Javaweb服务通知作业的状态。 情景: 客户端对JavaWeb服务进行同步Restful调用。 JavaWeb Service将作业详细信息输入数据库(类似于进行异步调用),并等待Windows Service的响应(这是对JavaWeb Service的新HT

  • 我的情况是,我们目前正在编写一个使用Node的在线应用程序。服务器端的js和WebSocket侦听器。我们有两个不同的部分:一个是服务页面,另一个是使用节点。js和express ejs,另一个是完全不同的应用程序,只包含套接字。用于WebSocket的io库。现在我们来讨论WebSocket部分的可伸缩性问题。 我们发现的一个解决方案是使用redis并在服务器之间共享套接字信息,但由于体系结构的