Исключение при отправке большого запроса на мыло

Существует веб-сервис, развернутый на tomcat 6 и доступный через apache-cxf 2.3.3. Сгенерированные источники заглушки с использованием wsdl2java, чтобы иметь возможность вызывать эту службу.

Все было хорошо, пока я не отправил большой запрос (~ 1 МБ). Этот запрос не был обработан и завершился ошибкой, за исключением:

Interceptor for {http://localhost/}ResourceAllocationServiceSoapService has thrown      
exception, unwinding now org.apache.cxf.binding.soap.SoapFault:
Error reading XMLStreamReader.
...
com.ctc.wstx.exc.WstxEOFException: Unexpected EOF in prolog 
at [row,col {unknown-source}]: [1,0]

Здесь какая-то максимальная длина запроса, я полностью застрял с этим.


person Vladimir    schedule 15.03.2011    source источник


Ответы (3)


Предложение Владимира сработало. Этот код ниже поможет другим понять, куда поместить 1000000.

public void handleMessage(SoapMessage message) throws Fault { 
        // Get message content for dirty editing...

    InputStream inputStream = message.getContent(InputStream.class);

    if (inputStream != null)
    {
        String processedSoapEnv = "";
        // Cache InputStream so it can be read independently
        CachedOutputStream cachedInputStream = new CachedOutputStream(1000000);
        try {
            IOUtils.copy(inputStream,cachedInputStream);
            inputStream.close();
            cachedInputStream.close();

            InputStream tmpInputStream = cachedInputStream.getInputStream();
            try{
                String inputBuffer = "";
                int data;
                while((data = tmpInputStream.read()) != -1){
                    byte x = (byte)data;
                    inputBuffer += (char)x;
                }
                /**
                  * At this point you can choose to reformat the SOAP
                  * envelope or simply view it just make sure you put
                  * an InputStream back when you done (see below)
                  * otherwise CXF will complain.
                  */
                processedSoapEnv = fixSoapEnvelope(inputBuffer);
            }
            catch(IOException e){

            }
        }
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        // Re-set the SOAP InputStream with the new envelope

        message.setContent(InputStream.class,new ByteArrayInputStream( processedSoapEnv.getBytes()));

        /**
         * If you just want to read the InputStream and not
         * modify it then you just need to put it back where
         * it was using the CXF cached inputstream
         *
         * message.setContent(InputStream.class,cachedInputStream.getInputStream());
        */
    }       


} 
person Wonka's Code Factory    schedule 25.04.2012

Я понял, что было не так. На самом деле это была ошибка внутри кода перехватчика:

CachedOutputStream requestStream = new CachedOutputStream()

Когда я заменил это на

 CachedOutputStream requestStream = new CachedOutputStream(1000000);

вещи начинают работать нормально.

Таким образом, запрос просто транкализировался во время копирования потоков.

person Vladimir    schedule 17.03.2011
comment
Куда вы добавили этот CachedOutputStream requestStream = new CachedOutputStream(1000000); Смотрите, я также сталкиваюсь с той же проблемой - person unknown; 06.03.2012

Я сталкиваюсь с той же проблемой получения «com.ctc.wstx.exc.WstxEOFException: неожиданный EOF в прологе» при использовании класса CachedOutputStream.

Глядя на источники класса CachedOutputStream, порог используется для переключения между хранением данных потока из «в памяти» в «файл».
Если поток работает с данными, которые превышают пороговое значение, он сохраняется в файле, поэтому следующий код сломается.

IOUtils.copy(inputStream,cachedInputStream);
inputStream.close();
cachedInputStream.close(); //closes the stream, the file on disk gets deleted
InputStream tmpInputStream = cachedInputStream.getInputStream(); //returned tmpInputStream is brand *empty* one
// ... reading tmpInputStream here will produce WstxEOFException 

Увеличение «порога» действительно помогает, так как все потоковые данные хранятся в памяти, и в таком сценарии вызов cachedInputStream.close() на самом деле не закрывает базовую реализацию потока, поэтому его можно прочитать позже.

Вот «исправленная» версия приведенного выше кода (по крайней мере, она работала без исключения для меня)

IOUtils.copy(inputStream,cachedInputStream);
inputStream.close();
InputStream tmpInputStream = cachedInputStream.getInputStream();
cachedInputStream.close();
// reading from tmpInputStream here works fine

Временный файл удаляется, когда close() вызывается для tmpInputStream и на него больше нет других ссылок, см. исходный код CachedOutputStream.maybeDeleteTempFile()

person Mateusz K    schedule 26.07.2012