Node.js - получить необработанное тело запроса с помощью Express

Ответы:

89

Редактировать 2: Версия 1.15.2 модуля парсера тела вводит необработанный режим , который возвращает тело как буфер . По умолчанию он также автоматически выполняет распаковку deflate и gzip. Пример использования:

var bodyParser = require('body-parser');
app.use(bodyParser.raw(options));

app.get(path, function(req, res) {
  // req.body is a Buffer object
});

По умолчанию optionsобъект имеет следующие параметры по умолчанию:

var options = {
  inflate: true,
  limit: '100kb',
  type: 'application/octet-stream'
};

Если вы хотите, чтобы ваш необработанный синтаксический анализатор анализировал другие типы MIME, кроме application/octet-stream, вам нужно будет изменить его здесь. Он также будет поддерживать сопоставление с подстановочными знаками, например */*или */application.


Примечание . Следующий ответ относится к версиям до Express 4, в которых промежуточное ПО все еще было в комплекте с фреймворком. Современный эквивалент - модуль body-parser , который нужно устанавливать отдельно.

rawBodyНедвижимость Экспресс когда - то была доступна, но удалены , начиная с версии 1.5.1. Чтобы получить необработанное тело запроса, перед использованием bodyParser необходимо добавить промежуточное ПО. Вы также можете прочитать обсуждение этого вопроса на GitHub здесь .

app.use(function(req, res, next) {
  req.rawBody = '';
  req.setEncoding('utf8');

  req.on('data', function(chunk) { 
    req.rawBody += chunk;
  });

  req.on('end', function() {
    next();
  });
});
app.use(express.bodyParser());

Это промежуточное ПО будет читать из фактического потока данных и сохранять его в rawBodyсвойстве запроса. Затем вы можете получить доступ к необработанному телу следующим образом:

app.post('/', function(req, res) {
  // do something with req.rawBody
  // use req.body for the parsed body
});

Изменить: кажется, что этот метод и bodyParser отказываются сосуществовать, потому что один из них будет потреблять поток запроса раньше другого, что приводит к тому, что тот, который является вторым, никогда не запускается end, поэтому никогда не вызывает next()и не зависает ваше приложение.

Самым простым решением, скорее всего, будет изменение источника bodyParser, который вы найдете в строке 57 синтаксического анализатора JSON Connect. Так будет выглядеть модифицированная версия.

var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){ buf += chunk });
req.on('end', function() {
  req.rawBody = buf;
  var first = buf.trim()[0];
  ...
});

Вы можете найти файл в этом месте:

/node_modules/express/node_modules/connect/lib/middleware/json.js.

гексацианид
источник
Кажется, мы не можем этого сделать. Если я добавлю этот код, события в \ node_modules \ express \ node_modules \ connect \ lib \ middleware \ urlencoded.js не будут запущены. req.on ("данные"), req.on ("конец") не запущены .
haitao_wu
После добавления вашего кода я обрабатываю свое сообщение, используя этот код app.post ("/ ajax", function (req, res) {res.send ('hello world, post');}); когда тип содержимого моего запроса - application / x-www-form-urlencoded, сервер не ответит «привет, мир, публикация»
haitao_wu
расположение файла неверно в моем случае .. У меня нет модуля подключения в node_modules экспресс (> 4.0.0), еще не нашел новое местоположение
Сэм Влоебергс
Connect не является зависимостью в Express 4 и поэтому не содержит модуль Body Parser. Если он вам все еще нужен, вы найдете его здесь .
гексацианид
1
@hexacyanide Не могли бы вы обновить свой ответ и включить ссылку на новейшее промежуточное ПО для body-parser ? Модуль теперь включает промежуточное ПО для парсера raw-body . Это может быть полезно для гуглеров, которые ищут способ получить необработанное тело.
eAbi
47

У меня есть решение, которое отлично сочетается с bodyParser, используя verifyобратный вызов в bodyParser. В этом коде я использую его, чтобы получить sha1 контента, а также необработанное тело.

app.use(bodyParser.json({
    verify: function(req, res, buf, encoding) {

        // sha1 content
        var hash = crypto.createHash('sha1');
        hash.update(buf);
        req.hasha = hash.digest('hex');
        console.log("hash", req.hasha);

        // get rawBody        
        req.rawBody = buf.toString();
        console.log("rawBody", req.rawBody);

    }
}));

Я новичок в Node.js и express.js (начался буквально вчера!), Поэтому мне хотелось бы услышать комментарии по этому решению.

Тьяго А.
источник
3
Мне очень нравится это решение. Я просто включил req.rawBody = buf.toString();и убрал остальное из verifyфункции, потому что это было все, что мне было нужно, и это прекрасно работало. Не нужно менять исходный код bodyParser!
Грег
+1 но теперь моя проблема в том, что мне нужна асинхронная функция, чтобы проверить, был ли этот запрос отправлен ранее или нет: /
Ренато Гама
3
очень хорошо. Могу я предложитьreq.rawBody = buf.toString(encoding);
Shaharsol
2
Будут захватываться только application/jsonзапросы
Павел Евстигнеев
35

Это решение сработало для меня:

var rawBodySaver = function (req, res, buf, encoding) {
  if (buf && buf.length) {
    req.rawBody = buf.toString(encoding || 'utf8');
  }
}

app.use(bodyParser.json({ verify: rawBodySaver }));
app.use(bodyParser.urlencoded({ verify: rawBodySaver, extended: true }));
app.use(bodyParser.raw({ verify: rawBodySaver, type: '*/*' }));

Когда я использую решение, req.on('data', function(chunk) { });оно не работает с фрагментированным телом запроса.

Павел Евстигнеев
источник
Это позаботилось обо всех основных сценариях входящих данных в различных частях запроса.
TWright
2
Я пытался проверить hmac для веб-перехватчика приложения Shopify, и это сработало для меня. Я примерно следовал этому примеру: gist.github.com/andjosh/5c4f0244914adfd312e4 .
Чад Джонсон
29

БУДЬТЕ ОСТОРОЖНЫ с этими другими ответами, поскольку они не будут правильно работать с bodyParser, если вы хотите также поддерживать json, urlencoded и т. Д. Чтобы заставить его работать с bodyParser, вы должны настроить свой обработчик так, чтобы он регистрировался только в Content-Typeзаголовках, которые вы заботиться, как и сам bodyParser.

Для того, чтобы получить сырье содержания тела запроса с Content-Type: "text/plain"в req.rawBodyвы можете сделать:

app.use(function(req, res, next) {
  var contentType = req.headers['content-type'] || ''
    , mime = contentType.split(';')[0];

  if (mime != 'text/plain') {
    return next();
  }

  var data = '';
  req.setEncoding('utf8');
  req.on('data', function(chunk) {
    data += chunk;
  });
  req.on('end', function() {
    req.rawBody = data;
    next();
  });
});
Нортрон
источник
3
+1. Я попробовал одно из вышеперечисленных решений, а затем все мои сообщения GET и json не работали. Приведенные выше решения технически верны для вопроса, но если вы обрабатываете более разнообразные запросы с данными в более чем одной форме, вам это понадобится.
Какие здесь данные? это переменная, которую мы отправляем из пользовательского интерфейса?
Сарас Арья
app.use(bodyParser.urlencoded({limit: '80mb', extended: true})); app.use(bodyParser.json({limit: '80mb'})); app.use(bodyParser.raw({type: 'application/octet-stream'})) Это тоже подойдет.
Сумья Канти
15

Это вариант ответа на гексацианид выше. Это промежуточное ПО также обрабатывает событие data, но не ожидает, пока данные будут использованы, перед вызовом next. Таким образом, промежуточное программное обеспечение и bodyParser могут сосуществовать, параллельно потребляя поток.

app.use(function(req, res, next) {
  req.rawBody = '';
  req.setEncoding('utf8');

  req.on('data', function(chunk) { 
    req.rawBody += chunk;
  });

  next();
});
app.use(express.bodyParser());

Оферей
источник
2
Похоже, это не работает с длинными телами, которые рано обрезаются.
Адам Локхарт,
Сработал отлично, спас меня. Спасибо.
hakazvaka
Я подтверждаю, что это работает и для больших файлов. Я попытался отправить текстовый файл размером 1,5 МБ, и все данные были получены правильно. Спасибо
ATOzTOA
@AdamLockhart - какого размера ваши запросы были сокращены?
UpTheCreek
@UpTheCreek, давненько. Не уверена. В моих последних материалах этот фрагмент не используется, но если другие не сообщают о проблемах, возможно, это ошибка, которая была исправлена.
Адам Локхарт,
-1

Используйте body-parser. Разберите тело таким, каким оно будет:

app.use(bodyParser.text());

app.use(bodyParser.urlencoded());

app.use(bodyParser.raw());

app.use(bodyParser.json());

т.е. Если вы хотите получить необработанный текстовый файл, запустите .text().

Это то, что сейчас поддерживает body-parser

мяук
источник