@Azik28

Как отправить ответ на запрос не сразу, а после определенного количества времени?

Я отправляю изображение с клиента Андроид на сервер Node.js, где оно обрабатывается Python программой. Я связываю Node.js с Python программой посредством пакета или библиотеки Python-Shell из NPM. Мне нужно отправить результат обработки обратно клиенту, как ответ на запрос.

Но из-за асинхронной архитектуры Node.js, ответ отправляется сразу, не дожидаясь выпонения и завершения обработки, которая занимает где-то 30-40 секунд. В результате, Андроид клиент получает пустой ответ.

К тому же, я не могу использовать res.write() несколько раз. После того как я использовал его однажды, я полагаю, что соединение разрывается. Поэтому у меня не получается использовать res.write() или res.send() в обработчике событий. И поэтому я накапливаю все сообщения из Python программы на Node.js сервер в отдельный массив, который пытаюсь отправить, но опять же необходимо дожидаться выполнения Python программы.

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

Код Node.js
app.post('/', rawBody, function (req, res) {
//rawBody is a function that receives chunks of image binary and creates a req.rawBody

if (req.rawBody && req.bodyLength > 0) {
    console.log("entered file writing");
    var timestamp = new Date().getTime().toString();
    var filename = 'Image'+timestamp+'.jpg';
    fs.writeFile(filename, req.rawBody);
    fs.writeFile('imagelist.txt', __dirname+ '/' + filename);
    //here I create an instance of PythonShell and execution of //testfile.py starts
    var pyshell = new PythonShell('testfile.py', options);
    //I store in the output all the messages from Python
    var output = [];
    // whenever python prints any output this event is emitted
    pyshell.on('message', function(message, error){
            if (error) throw error;
            console.log(message);
            //try to write the message into response
            res.write(message);
            output.push(message);
    });

    pyshell.end(function(err) {

            console.log('python finished');
            //send response
            res.end();
    });

    pyshell.on('error',function(err){
            console.log(err);
    });

} else {
    res.send(500);
}

});


Вот как я получаю ответ на Андроид клиенте:

HttpURLConnection conn = (HttpURLConnection) url.openConnection();
       conn.setRequestMethod("POST");

       conn.setDoInput(true);
       conn.setDoOutput(true);
       conn.setRequestProperty("Connection", "Keep-Alive");
       conn.setRequestProperty("Cache-Control", "no-cache");

        conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
        conn.setReadTimeout(80000);
        conn.setConnectTimeout(80000);
        InputStream in = new BufferedInputStream(conn.getInputStream());

        BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(in));
        String line = "";
        StringBuilder stringBuilder = new StringBuilder();

       while (true) {
                    line = responseStreamReader.readLine();
                    if (line != null) {
                        System.out.print("accepted new response particle " + line);
                        stringBuilder.append(line).append("\n");
                        System.out.print(stringBuilder.toString());
                        break;
                    } 
          }
          //old version
        /*while ((line = responseStreamReader.readLine()) != null) {
            stringBuilder.append(line).append("\n");
            //System.out.print(stringBuilder.toString());
        }*/
        responseStreamReader.close();

        String response = stringBuilder.toString();
        System.out.println(response);

        in.close();
        conn.disconnect();
  • Вопрос задан
  • 874 просмотра
Пригласить эксперта
Ответы на вопрос 1
MarcusAurelius
@MarcusAurelius Куратор тега Node.js
автор Impress Application Server для Node.js
Замените все синхронные операции типа writeFileSync на асинхронные аналоги, чтобы они не блокировали поток обработки, и отправляйте ответ через 30-40 секунд, даже через 3-5 минут нормально, это будет работать как лонг-пулинг, т.е. пока HTTP таймаут не закончится. Только нельзя блокировать поток обработки, иначе параллельные запросы не будут приниматься.
UPD: и еще заметил, что req.rawBody это у Вас функция, которая читает и склеивает все чанки файла, так вот она без колбека, Вы ее сделали синхронной тоже, это плохо, посмотрите как я получаю серию чанков и клею их: impress.application.js#L479-L489 В общем, видно, что Вы только частично освоили асинхронный подход и смешиваете его с синхронным, что и не позволяет сделать параллельную обработку нескольких таких запросов в одном потоке ноды. Использовать файловые потоки и pipe тут не обязательно, но можно. Только тогда нужно запус питона повесить на событие req.on('end',...) или file.res.on('finish',...) того FileStream в который пайпите req.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы