如何在CXF响应中添加用户HTTP标头?

时间:2015-07-09 13:47:42

标签: web-services cxf

由于某种原因,没有'内容长度' CXF响应中的HTTP标头。 我已经决定实现拦截器来实现它,但不幸的是,在发送的数据中没有添加标头(使用Wireshark拦截)。我可以设置断点,我可以看到拦截器被调用。怎么了?

/**
 * Adds Content-Length header for the outcoming messages
 */
public class AddContentLengthInterceptor extends AbstractLoggingInterceptor {

    private static final String CONTENT_LENGTH_ADDED = AddContentLengthInterceptor.class.getName() + ".log-setup";

    public AddContentLengthInterceptor(String phase) {
        super(phase);
        addBefore(StaxOutInterceptor.class.getName());
    }
    public AddContentLengthInterceptor() {
        this(Phase.PRE_PROTOCOL); // before streaming
    }

    @Override
    protected Logger getLogger() {
        return null;
    }

    @Override
    public void handleMessage(Message message) throws Fault {
        final OutputStream os = message.getContent(OutputStream.class);
        final Writer iowriter = message.getContent(Writer.class);
        if (os == null && iowriter == null) {
            return;
        }

        // ignore double processing of the message
        boolean hasAddedHeader = message.containsKey(CONTENT_LENGTH_ADDED);
        if (!hasAddedHeader) {
            message.put(CONTENT_LENGTH_ADDED, Boolean.TRUE);
            if (os != null) {
                // Write the output while caching it for adding header later
                final CacheAndWriteOutputStream newOut = new CacheAndWriteOutputStream(os);
                message.setContent(OutputStream.class, newOut);
                newOut.registerCallback(new LoggingCallback(message, os));
            }
        }
    }

    class LoggingCallback implements CachedOutputStreamCallback {

        private final Message message;
        private final OutputStream origStream;

        public LoggingCallback(final Message msg, final OutputStream os) {
            this.message = msg;
            this.origStream = os;
        }

        public void onFlush(CachedOutputStream cos) {

        }

        public void onClose(CachedOutputStream cos) {
            long contentLength = cos.size();

            Map<String, List<String>> headers = (Map<String, List<String>>) message.get(Message.PROTOCOL_HEADERS);
            if (headers == null)
                headers = new HashMap<String, List<String>>();
            headers.put("Content-Length", Arrays.asList(String.valueOf(contentLength)));
            message.put(Message.PROTOCOL_HEADERS, headers);

            try {
                // empty out the cache
                cos.lockOutputStream();
                cos.resetOut(null, false);
            } catch (Exception ex) {
                //ignore
            }
            message.setContent(OutputStream.class, origStream);
        }
    }
}

现在创建了服务器端端点:

    mediaService = new MediaService(ip, rtspPort, streamUri);
    ProviderImpl provider = new ProviderImpl();
    mediaEndpoint = (EndpointImpl) provider.createEndpoint(null, mediaService);
    String mediaServiceURL = MessageFormat.format("http://{0}:{1}/onvif/media_service", ip, String.valueOf(port));
    mediaEndpoint.publish(mediaServiceURL);

    // add "Content-Length" header
    mediaEndpoint.getServer().getEndpoint().getOutInterceptors().add(contentLengthInterceptor);

1 个答案:

答案 0 :(得分:1)

我认为您正在使用Transfer-Encoding作为分块。这导致没有内容长度标头,因为它在RFC中以这种方式定义。

  

消息不得包含Content-Length头字段和a   非身份转移编码。如果消息确实包含a   非身份转移编码,必须忽略内容长度。

我不完全确定,但是cxf会删除你的标题,因为它是不允许的,或者它设置但子图层会将其删除。据我所知,cxf使用HttpUrlConnection来传输你的消息。并且该层在正常情况下设置Content-length头。但由于您正在使用分块传输,该层可能会覆盖它。

要修复它,您必须更改Transfer-Encoding。由于CXF本身设置了内容长度标题,因此您不再需要编写拦截器。

顺便说一句,如果你使用自定义标题,你会发现你的拦截器就像一个魅力。

相关问题