Обработка множества одновременных запросов AJAX с помощью действия struts2

У меня есть действие struts2, которое отвечает на запрос AJAX, принимая некоторые параметры запроса, вызывая удаленную службу, которая возвращает данные XML, затем преобразует данные через XSL и возвращает полученный XHTML через результат потока. Ответ отличается в зависимости от заданных параметров.

Вот класс действий с кучей удаленных вещей:

public class ServiceHandler extends ActionSupport {
    private ByteArrayInputStream inputStream;

    public String execute(){

        String response = "";

        // Get request parameters
        // Make a request to a remote server via an http connection
        // Transform result via XSL

        //uses dom4j for XML/XSL stuff
        //this should never be empty
        response = resultDoc.asXML();

        inputStream = new ByteArrayInputStream(response.getBytes()); 
        return "success";
    }

    public ByteArrayInputStream getInputStream(){
        return inputStream;
    }
}

И вот важные биты struts.xml:

<action name="sh" class="ServiceHandler">
    <result name="success" type="stream">
        <param name="contentType">text/html</param>
        <param name="contentDisposition">inline;filename="response.html"</param>
        <param name="bufferSize">1024</param>
        <param name="allowCaching">false</param>
    </result>
</action>

Моя проблема заключается в том, что когда у меня одновременно выполняется несколько запросов, все из которых вызывают действие ServiceHandler, иногда ответ полностью пуст (никогда не должен происходить), иногда ответ обрезается в начале или в конце на некоторую случайную величину, и иногда ответы переключаются, так что запросчик AJAX получает неправильный ответ.

Я знаю, что это проблема безопасности потоков, и я переместил все важные определения переменных в метод execute(), чтобы они не были переменными экземпляра (и, следовательно, общими для всех). Единственная интересная переменная, которая является переменной экземпляра, — это inputStream, и я рассматриваю это как причину своих проблем.

Есть ли способ сделать переменную inputStream потокобезопасной? Или есть другое решение, которого я не вижу?


person Adam Plumb    schedule 25.06.2009    source источник


Ответы (3)


Я знаком только со Struts 1, но взгляните на DonwloadAction. Или просто используйте обычное действие Struts, запишите результат непосредственно в объект ответа и верните null как forward.

person GClaramunt    schedule 25.06.2009

Я вообще не увлекаюсь Struts 2, но если вам действительно нужно вернуть результат «успех» и у вас нет возможности напрямую писать в вывод, это выглядит как хорошее место для использования ThreadLocal, чтобы ваш поток оставался локальным для текущего потока. (Дополнительную информацию о шаблоне см. также в статье Википедии о локальном хранилище потока. )

person Henning    schedule 25.06.2009
comment
Мне не нужно возвращать успех, и struts2 ограничивает меня только в том, что я могу и не могу делать. Если я смогу найти способ вывода напрямую без использования переменной экземпляра, я сделаю это. - person Adam Plumb; 26.06.2009
comment
Нашел способ сделать это, и прямое письмо, похоже, решило мою проблему. - person Adam Plumb; 26.06.2009

Спасибо Хеннингу за то, что он ведет меня в правильном направлении. Я не думал о записи непосредственно в поток вывода ответа, так как он нигде не упоминается в документации struts2.

Преимущество записи ответа непосредственно в выходной поток заключается в том, что вам не нужно создавать экземпляр объекта для inputStream. Это сохраняет все данные в методе execute(), который защищен от других потоков.

Вот модифицированный класс действий, который записывает непосредственно в выходной поток и возвращает нулевой результат.

import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;

public class ServiceHandler extends ActionSupport {
    public String execute(){

        String response = "";

        // Get request parameters
        // Make a request to a remote server via an http connection
        // Transform result via XSL

        //uses dom4j for XML/XSL stuff
        //this should never be empty
        response = resultDoc.asXML();

        HttpServletResponse httpResponse = ServletActionContext.getResponse();
        try{
            httpResponse.getOutputStream().print(response);
        }
        catch(IOException e){
            return "failure";
        }

        return null;
    }
}

Похоже, это решило проблемы, которые у меня были.

person Adam Plumb    schedule 25.06.2009