จะประมวลผลข้อมูล POST ใน Node.js ได้อย่างไร?


637

คุณดึงข้อมูลในแบบฟอร์ม ( form[method="post"]) และอัพโหลดไฟล์ที่ส่งจากPOSTวิธีHTTP ในNode.js อย่างไรอย่างไร

ฉันอ่านเอกสารแล้ว googled และไม่พบอะไรเลย

function (request, response) {
    //request.post????
}

มีห้องสมุดหรือแฮ็คหรือไม่?

คำตอบ:


552

ถ้าคุณใช้Express (การพัฒนาเว็บประสิทธิภาพสูงสำหรับ Node.js) คุณสามารถทำได้ดังนี้:

HTML:

<form method="post" action="/">
    <input type="text" name="user[name]">
    <input type="text" name="user[email]">
    <input type="submit" value="Submit">
</form>

ลูกค้า API:

fetch('/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        user: {
            name: "John",
            email: "john@example.com"
        }
    })
});

Node.js: (ตั้งแต่ Express v4.16.0)

// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded());

// Parse JSON bodies (as sent by API clients)
app.use(express.json());

// Access the parse results as request.body
app.post('/', function(request, response){
    console.log(request.body.user.name);
    console.log(request.body.user.email);
});

Node.js: (สำหรับ Express <4.16.0)

const bodyParser = require("body-parser");

/** bodyParser.urlencoded(options)
 * Parses the text as URL encoded data (which is how browsers tend to send form data from regular forms set to POST)
 * and exposes the resulting object (containing the keys and values) on req.body
 */
app.use(bodyParser.urlencoded({
    extended: true
}));

/**bodyParser.json(options)
 * Parses the text as JSON and exposes the resulting object on req.body.
 */
app.use(bodyParser.json());

app.post("/", function (req, res) {
    console.log(req.body.user.name)
});

45
ฟังก์ชั่นนี้ใช้งานจริงในโมดูล BodyParser ในการเชื่อมต่อหากคุณต้องการใช้จุดเริ่มต้นระดับต่ำ
Julian Birch

14
ฉันสับสน name = "user [email]" สอดคล้องกับ request.body.email อย่างไร
sbose

36
พระเจ้า!! ฉันเริ่มบ้าต้องอ่าน 3 doumentations ในเวลาเดียวกันสำหรับกรอบงานเดียวกัน: / nodejs.org/api/http.html , senchalabs.org/connect & expressjs.com/guide.html
Salman von Abbas

15
app.use(express.bodyParser());เรื่องนี้ไม่ได้ทำงานสำหรับฉันจนกว่าฉันจะเพิ่ม
จิ๊บจ๊อย

13
Express คือโหนดสิ่งที่ jQuery คือ JS ฝั่งไคลเอ็นต์ ทุกครั้งที่ฉัน google ช่วยสำหรับโหนดฉันได้รับง่อยเหล่านี้ "ใช้ด่วน!" คำตอบ การแยกวิเคราะห์ข้อมูลโพสต์นั้นเป็นเรื่องยากหรือไม่
Shawn Whinnery

710

คุณสามารถใช้querystringโมดูล:

var qs = require('querystring');

function (request, response) {
    if (request.method == 'POST') {
        var body = '';

        request.on('data', function (data) {
            body += data;

            // Too much POST data, kill the connection!
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6)
                request.connection.destroy();
        });

        request.on('end', function () {
            var post = qs.parse(body);
            // use post['blah'], etc.
        });
    }
}

ตอนนี้ตัวอย่างเช่นถ้าคุณมีinputเขตข้อมูลที่มีชื่อageคุณสามารถเข้าถึงได้โดยใช้ตัวแปรpost:

console.log(post.age);

8
@thejh หืมนั่นเป็นจุดที่ดี แต่ก็ไม่ควรเพิ่มที่ยากดังนั้นฉันจะทิ้งตัวอย่างไว้เพื่อให้สิ่งต่าง ๆ เรียบง่าย
Casey Chu

72
การพัฒนาเว็บเซิร์ฟเวอร์ node.js เกิดขึ้นกับมิดเดิลแวร์ที่คุณต้องศึกษาเป็นเวลาหลายชั่วโมงเพื่อช่วยให้คุณประหยัดเวลาในการเข้ารหัส เอกสารที่ขาดแคลนเพียงอย่างเดียวเกือบทั้งหมดของพวกเขาให้ และใบสมัครของคุณก็ขึ้นอยู่กับเกณฑ์ของคนอื่นไม่ใช่ของคุณ บวกกับปัญหาด้านประสิทธิภาพจำนวนเท่าใดก็ได้
Juan Lanus

4
var POST = qs.parse(body); // use POST สำหรับ noobs อย่างฉันเท่านั้น: เมื่อชื่อของฟิลด์ข้อความอินพุตคือ "ผู้ใช้" Post.userจะแสดงข้อมูลของฟิลด์นั้น เช่นconsole.log(Post.user);
Michael Moeller

5
คุณสามารถใช้การreadableติดต่อกลับแทนการสร้างข้อมูลลงในสายอักขระ เมื่อมันถูกไล่ออกร่างกายก็จะพร้อมให้ใช้งานได้request.read();
Thomas Fankhauser

4
แจ้งให้ทราบreq.connection.destroy(); ว่าไม่ได้ป้องกันการเรียกกลับจากการถูกดำเนินการ! ตัวอย่างเช่นการเรียกกลับ "เมื่อสิ้นสุด" จะถูกดำเนินการกับเนื้อหาที่ถูกตัดทอน! นี้ไม่อาจเป็นสิ่งที่คุณต้องการ ...
collimarco

149

ตรวจสอบให้แน่ใจว่าได้ฆ่าการเชื่อมต่อหากมีคนพยายาม RAM ของคุณล้นหลาม!

var qs = require('querystring');

function (request, response) {
    if (request.method == 'POST') {
        var body = '';
        request.on('data', function (data) {
            body += data;
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6) { 
                // FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
                request.connection.destroy();
            }
        });
        request.on('end', function () {

            var POST = qs.parse(body);
            // use POST

        });
    }
}

53
คุณอาจส่งคืนรหัสข้อผิดพลาด HTTP 413 ได้ (คำขอมีขนาดใหญ่เกินไป)
neoascetic

1
@SSHThis: ไม่เป็น 1 * 10 ^ 6 = 1000000
thejh

@tq: ในกรณีนี้ POST [ชื่อ] (เช่น POST ["foo"])
thejh

2
var POST = qs.parse(body); // use POST สำหรับ noobs เท่านั้น: เมื่อชื่อของช่องป้อนข้อความคือ "ผู้ใช้" Post.user จะแสดงข้อมูลของฟิลด์นั้น เช่น console.log (Post.user);
Michael Moeller

2
มีใครช่วยถ้าฉันโพสต์ {'ชื่อ': 'Joe'} ฉันได้รับ {{'ชื่อ': 'โจ'}: ''} หลังจาก qs.Parse (POST) ...
แมตต์ Canty

118

คำตอบมากมายที่นี่ไม่ใช่วิธีปฏิบัติที่ดีอีกต่อไปหรือไม่อธิบายอะไรเลยดังนั้นฉันจึงเขียนสิ่งนี้

ข้อมูลพื้นฐานเกี่ยวกับ

เมื่อมีการเรียกการเรียกกลับของ http.createServer คือเมื่อเซิร์ฟเวอร์ได้รับส่วนหัวทั้งหมดสำหรับคำขอ แต่เป็นไปได้ว่ายังไม่ได้รับข้อมูลดังนั้นเราต้องรอ คำขอวัตถุ http (ก http.IncomingMessage เป็นต้น)เป็นจริงอ่าน กระแส ในสตรีมที่อ่านได้เมื่อใดก็ตามที่ข้อมูลจำนวนหนึ่งมาถึงเหตุการณ์จะถูกปล่อยออกมา (สมมติว่าคุณได้ลงทะเบียนการโทรกลับ) และเมื่อชิ้นข้อมูลทั้งหมดมาถึงเหตุการณ์จะถูกปล่อยออกมา นี่คือตัวอย่างเกี่ยวกับวิธีที่คุณฟังเหตุการณ์:data end

http.createServer((request, response) => {
  console.log('Now we have a http message with headers but no data yet.');
  request.on('data', chunk => {
    console.log('A chunk of data has arrived: ', chunk);
  });
  request.on('end', () => {
    console.log('No more data');
  })
}).listen(8080)

การแปลงบัฟเฟอร์เป็นสตริง

ถ้าคุณพยายามที่นี้คุณจะสังเกตเห็นชิ้นที่มีบัฟเฟอร์ หากคุณไม่ได้จัดการกับข้อมูลไบนารีและจำเป็นต้องทำงานกับสตริงแทนฉันขอแนะนำให้ใช้เมธอดrequest.setEncodingซึ่งทำให้สตริงการส่งกระแสข้อมูลตีความด้วยการเข้ารหัสที่กำหนดและจัดการอักขระหลายไบต์อย่างถูกต้อง

บัฟเฟอร์ชิ้นส่วน

ตอนนี้คุณอาจไม่สนใจแต่ละอันของมันเองดังนั้นในกรณีนี้คุณอาจต้องการบัฟเฟอร์แบบนี้:

http.createServer((request, response) => {
  const chunks = [];
  request.on('data', chunk => chunks.push(chunk));
  request.on('end', () => {
    const data = Buffer.concat(chunks);
    console.log('Data: ', data);
  })
}).listen(8080)

ที่นี่ คือการใช้Buffer.concatซึ่งจะเชื่อมต่อบัฟเฟอร์ทั้งหมดและคืนหนึ่งบัฟเฟอร์ใหญ่ คุณยังสามารถใช้โมดูล concat-streamซึ่งทำสิ่งเดียวกัน:

const http = require('http');
const concat = require('concat-stream');
http.createServer((request, response) => {
  concat(request, data => {
    console.log('Data: ', data);
  });
}).listen(8080)

แยกเนื้อหา

หากคุณกำลังพยายามที่จะยอมรับการส่งแบบฟอร์ม POST แบบ HTML โดยไม่มีไฟล์หรือส่งjQuery ajax การโทรด้วยประเภทเนื้อหาเริ่มต้นแล้วประเภทเนื้อหาจะอยู่application/x-www-form-urlencodedกับuft-8เข้ารหัส คุณสามารถใช้โมดูลการสอบถามเพื่อยกเลิกการทำให้เป็นอนุกรมและเข้าถึงคุณสมบัติ:

const http = require('http');
const concat = require('concat-stream');
const qs = require('querystring');
http.createServer((request, response) => {
  concat(request, buffer => {
    const data = qs.parse(buffer.toString());
    console.log('Data: ', data);
  });
}).listen(8080)

หากประเภทเนื้อหาของคุณคือ JSON แทนคุณสามารถใช้ JSON.parseแทนqs.parse

หากคุณกำลังจัดการกับไฟล์หรือจัดการประเภทเนื้อหาแบบหลายส่วนดังนั้นในกรณีนี้คุณควรใช้สิ่งที่น่ากลัวซึ่งจะขจัดความเจ็บปวดทั้งหมดออกจากการจัดการกับมัน ดูคำตอบอื่น ๆของฉันที่ฉันได้โพสต์ลิงก์และโมดูลที่มีประโยชน์สำหรับเนื้อหาหลายส่วน

การเป่า

หากคุณไม่ต้องการที่จะแยกเนื้อหา แต่แทนที่จะส่งไปยังที่อื่นตัวอย่างเช่นส่งไปยังคำขอ http อื่นเป็นข้อมูลหรือบันทึกลงในไฟล์ที่ฉันแนะนำ ไพพ์มากกว่าการบัฟเฟอร์มันจะน้อยลง รหัสจัดการกับแรงกดดันด้านหลังได้ดีขึ้นมันจะใช้หน่วยความจำน้อยลงและในบางกรณีเร็วขึ้น

ดังนั้นหากคุณต้องการบันทึกเนื้อหาลงในไฟล์:

 http.createServer((request, response) => {
   request.pipe(fs.createWriteStream('./request'));
 }).listen(8080)

การ จำกัด ปริมาณข้อมูล

ตามคำตอบอื่น ๆ โปรดจำไว้ว่าลูกค้าที่ประสงค์ร้ายอาจส่งข้อมูลจำนวนมากเพื่อให้แอปพลิเคชันของคุณพังหรือเติมหน่วยความจำของคุณเพื่อป้องกันที่ทำให้แน่ใจว่าคุณปล่อยคำขอที่ปล่อยข้อมูลผ่านขีด จำกัด ที่แน่นอน หากคุณไม่ได้ใช้ห้องสมุดเพื่อจัดการกับข้อมูลที่เข้ามา ฉันขอแนะนำให้ใช้บางอย่างเช่นเครื่องวัดกระแสซึ่งสามารถยกเลิกคำขอได้หากถึงขีด จำกัด ที่ระบุ:

limitedStream = request.pipe(meter(1e7));
limitedStream.on('data', ...);
limitedStream.on('end', ...);

หรือ

request.pipe(meter(1e7)).pipe(createWriteStream(...));

หรือ

concat(request.pipe(meter(1e7)), ...);

โมดูล NPM

ขณะที่ฉันอธิบายข้างต้นเกี่ยวกับวิธีที่คุณสามารถใช้เนื้อหาคำขอ HTTP สำหรับการบัฟเฟอร์และการแยกวิเคราะห์เนื้อหาฉันขอแนะนำให้ใช้หนึ่งในโมดูลเหล่านี้แทนที่จะใช้งานด้วยตัวคุณเองเนื่องจากพวกเขาอาจจัดการกับกรณีขอบได้ดีขึ้น สำหรับการแสดงผมขอแนะนำให้ใช้ตัวแยกวิเคราะห์ สำหรับไม้สัก, มีโมดูลที่คล้ายกัน

ถ้าคุณไม่ใช้เฟรมเวิร์กร่างกายก็ค่อนข้างดี


ขอบคุณฉันใช้รหัสของคุณและฉันได้รับข้อความซ้ำซ้อน เป็นไปได้ไหมว่าตัวแปรrequestนั้นถูกนำมาใช้ซ้ำและrequest.on('end')ถูกเรียกหลายครั้ง? ฉันจะหลีกเลี่ยงสิ่งนั้นได้อย่างไร
Yan King Yin

ฉันไม่สามารถบอกได้ว่าทำไมถึงไม่เห็นรหัสของคุณ โปรดทราบว่าสำหรับทุกคำขอrequest.on('end', ...)จะถูกเรียก
Farid Nouri Neshat

มันอาจจะไม่เกี่ยวข้องกับรหัสของคุณฉันทำเหตุการณ์เซิร์ฟเวอร์ที่ส่งและอาจจะเมาขึ้น ... รหัสของคุณทำงานได้ดีขอบคุณล่ะค่ะ :)
แยนคิงหยิน

ประสิทธิภาพของเอฟเฟกต์นี้อย่างไรเมื่อเปรียบเทียบกับการประมวลผลคำขอ GET ที่ไม่มีตัวจัดการ 'สิ้นสุด' เช่นไม่มีบัฟเฟอร์บัฟเฟอร์?
JSON

1
นี่คือคำตอบที่ดีที่สุดสำหรับคำถาม 🧐
montrealist

103

นี่คือ wrapper ไม่มีกรอบที่ง่ายมากตามคำตอบอื่น ๆ และบทความที่โพสต์ที่นี่:

var http = require('http');
var querystring = require('querystring');

function processPost(request, response, callback) {
    var queryData = "";
    if(typeof callback !== 'function') return null;

    if(request.method == 'POST') {
        request.on('data', function(data) {
            queryData += data;
            if(queryData.length > 1e6) {
                queryData = "";
                response.writeHead(413, {'Content-Type': 'text/plain'}).end();
                request.connection.destroy();
            }
        });

        request.on('end', function() {
            request.post = querystring.parse(queryData);
            callback();
        });

    } else {
        response.writeHead(405, {'Content-Type': 'text/plain'});
        response.end();
    }
}

ตัวอย่างการใช้งาน:

http.createServer(function(request, response) {
    if(request.method == 'POST') {
        processPost(request, response, function() {
            console.log(request.post);
            // Use request.post here

            response.writeHead(200, "OK", {'Content-Type': 'text/plain'});
            response.end();
        });
    } else {
        response.writeHead(200, "OK", {'Content-Type': 'text/plain'});
        response.end();
    }

}).listen(8000);

ไม่ควรย้ายเช็คนี้ไปยังมิดเดิลแวร์ที่แยกต่างหากเพื่อให้สามารถตรวจสอบคำขอที่มีขนาดใหญ่เกินไปสำหรับคำขอโพสต์ / วางทั้งหมด
Pavel Nikolov

@PavelNikolov สิ่งนี้มีความหมายส่วนใหญ่สำหรับงานที่รวดเร็วและสกปรกมิฉะนั้นอาจจะดีกว่าถ้าใช้ Express เช่นคำตอบที่ยอมรับได้ที่นี่แนะนำ (ซึ่งอาจดูแลการจัดการคำขอขนาดใหญ่เช่นกัน) อย่าลังเลที่จะแก้ไขและ "แยก" ตามที่คุณต้องการ
Mahn

แล้วเมธอด .read () เป็นอย่างไร โมดูล http นั้นไม่รองรับหรือไม่ เช่น. response.read ()
BT

เฮ้แค่อยากรู้อยากเห็น - ทำไมคุณวางน้ำหนักบรรทุกลงในวัตถุตอบสนอง (response.post) แทนที่จะเป็นวัตถุขอ
Jotham

@Jotham คำถามที่ดี ... ฉันมีความคิดว่าทำไมไม่ได้ผมสังเกตเห็นว่าก่อนหน้านี้ แต่มีเหตุผลที่ว่าทำไมมันไม่ควรมากกว่าตรรกะมากขึ้นresponse.post request.postฉันอัพเดทโพสต์แล้ว
Mahn

83

มันจะสะอาดขึ้นถ้าคุณเข้ารหัสข้อมูลของคุณไปยังJSONจากนั้นส่งไปที่ Node.js

function (req, res) {
    if (req.method == 'POST') {
        var jsonString = '';

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

        req.on('end', function () {
            console.log(JSON.parse(jsonString));
        });
    }
}

1
นี่คือสิ่งที่ได้ผลสำหรับฉัน กลับกลายเป็นว่าโซลูชันอื่น ๆ ส่งคืนสตริงที่ดูเหมือน JSON แต่ไม่ได้แยกวิเคราะห์ แทนที่จะqs.parse(), JSON.parse()หันร่างกายเป็นสิ่งที่สามารถใช้งานได้ ตัวอย่าง: แล้วการเข้าถึงข้อมูลที่มีvar post = JSON.parse(body); post.fieldname(คุณธรรมของเรื่องราวถ้าคุณสับสนเกี่ยวกับสิ่งที่คุณเห็นอย่าลืมtypeof!)
wmassingham

12
เพิ่งทราบว่าคุณต้องลองใช้ฟังก์ชั่น JSON.parse เพราะถ้าฉันต้องการที่จะทำให้แอปพลิเคชันของคุณล้มเหลวเพียงแค่ส่งเนื้อหาที่มีข้อความดิบ
ecarrizo

คุณควรใช้request.setEncodingเพื่อให้งานนี้ถูกต้องมิฉะนั้นอาจจัดการอักขระที่ไม่ใช่ ASCII ได้อย่างไม่ถูกต้อง
Farid Nouri Neshat

37

สำหรับทุกคนที่สงสัยว่าจะทำสิ่งเล็ก ๆ น้อย ๆ นี้ได้อย่างไรโดยไม่ต้องติดตั้งเฟรมเวิร์กเว็บ การผลิตแทบจะไม่พร้อม แต่ดูเหมือนว่าจะใช้งานได้

function handler(req, res) {
    var POST = {};
    if (req.method == 'POST') {
        req.on('data', function(data) {
            data = data.toString();
            data = data.split('&');
            for (var i = 0; i < data.length; i++) {
                var _data = data[i].split("=");
                POST[_data[0]] = _data[1];
            }
            console.log(POST);
        })
    }
}

ในที่สุดการแก้ปัญหาการทำงานอย่างเต็มรูปแบบสำหรับปัญหาแปลก ๆ นี้ .. นอกจากนี้คำตอบก่อนหน้าช่วยได้มากที่จะเข้าใจว่าทำไมไม่มีข้อมูลภายในคำขอเมื่อการติดต่อกลับเริ่มขึ้น .. ขอบคุณมาก!
luis-br

3
1) คำตอบนี้ถือว่าข้อมูลเป็นสตริง สมมติฐานที่ไม่ดีในกรณีทั่วไป 2) คำตอบนี้อนุมานว่าข้อมูลมาถึงหนึ่งก้อน มิฉะนั้นการแยกโดย '=' จะให้ผลลัพธ์ที่ไม่คาดคิด สมมติฐานที่ไม่ดีในกรณีทั่วไป
Konstantin

@ Konstantin จริงๆแล้วคำตอบนี้ถือว่าข้อมูลเป็น Buffer ลองดู. stackoverflow.com/questions/14551194/… นอกจากนี้ยังมี millermedeiros.github.io/mdoc/examples/node_api/doc/…
Shawn Whinnery

16

คุณสามารถใช้body-parserมิดเดิลแวร์การแยกวิเคราะห์เนื้อความ Node.js

โหลดครั้งแรก body-parser

$ npm install body-parser --save

ตัวอย่างรหัสบางส่วน

var express = require('express')
var bodyParser = require('body-parser')

var app = express()

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())


app.use(function (req, res) {
  var post_data = req.body;
  console.log(post_data);
})

เอกสารเพิ่มเติมสามารถพบได้ที่นี่



9

นี่คือวิธีที่คุณสามารถทำได้ถ้าคุณใช้node-formidable :

var formidable = require("formidable");

var form = new formidable.IncomingForm();
form.parse(request, function (err, fields) {
    console.log(fields.parameter1);
    console.log(fields.parameter2);
    // ...
});

ฉันประสบปัญหากับเส้นทางเมื่อฉันพยายามใช้พา ธ หรือชื่อพา ธ + เพื่อเข้าถึงไฟล์ด้วย lwip.open (พา ธ หรือเส้นทาง + ชื่อฉันได้รับข้อผิดพลาดเป็นรูปภาพที่ไม่ได้รับ
Lion789

7

หากคุณต้องการใช้ pure Node.js คุณอาจดึงข้อมูล POST ตามที่แสดงด้านล่าง:

// Dependencies
const StringDecoder = require('string_decoder').StringDecoder;
const http = require('http');

// Instantiate the HTTP server.
const httpServer = http.createServer((request, response) => {
  // Get the payload, if any.
  const decoder = new StringDecoder('utf-8');
  let payload = '';

  request.on('data', (data) => {
    payload += decoder.write(data);
  });

  request.on('end', () => {
    payload += decoder.end();

    // Parse payload to object.
    payload = JSON.parse(payload);

    // Do smoething with the payload....
  });
};

// Start the HTTP server.
const port = 3000;
httpServer.listen(port, () => {
  console.log(`The server is listening on port ${port}`);
});


6

1) ติดตั้ง'body-parser'จาก npm

2) จากนั้นในของคุณapp.ts

var bodyParser = require('body-parser');

3) จากนั้นคุณต้องเขียน

app.use(bodyParser.json())

ในโมดูลapp.ts

4) จำไว้ว่าคุณรวม

app.use(bodyParser.json())

ในด้านบนหรือก่อนการประกาศโมดูลใด ๆ

Ex:

app.use(bodyParser.json())
app.use('/user',user);

5) จากนั้นใช้

var postdata = req.body;

5

หากคุณไม่ต้องการรวมข้อมูลกับการdataโทรกลับคุณสามารถใช้การreadableติดต่อกลับดังนี้:

// Read Body when Available
request.on("readable", function(){
  request.body = '';
  while (null !== (request.body += request.read())){}
});

// Do something with it
request.on("end", function(){
  request.body //-> POST Parameters as String
});

วิธีการนี้จะปรับเปลี่ยนคำขอที่เข้ามา แต่ทันทีที่คุณตอบสนองคำขอของคุณจะถูกรวบรวมอย่างสมบูรณ์ดังนั้นจึงไม่ควรมีปัญหา

วิธีการขั้นสูงคือการตรวจสอบขนาดร่างกายก่อนถ้าคุณกลัวร่างใหญ่


วิธีที่สะดวกในการทำ แต่คุณจะ "ตรวจสอบขนาดร่างกายก่อน" ในแบบที่ไม่สามารถถูกหลอกโดยคำขอที่เป็นอันตรายได้อย่างไร
doug65536

requestเป็นโหนด stream.js ปกติดังนั้นคุณสามารถตรวจสอบrequest.headersความยาวของเนื้อความและยกเลิกคำร้องขอหากจำเป็น
Thomas Fankhauser

1
@ThomasFankhauser ความยาวลำตัวในส่วนหัวอาจไม่ใช่ค่าที่ถูกต้องหรือแม้กระทั่งมีอยู่ วิธีที่ถูกต้องคือเมื่อร่างกายมาถึงและคุณกำลังบัฟเฟอร์คุณตรวจสอบขนาดเพื่อให้แน่ใจว่ามันไม่ผ่านขีด จำกัด
Farid Nouri Neshat

4

มีหลายวิธีที่จะทำ อย่างไรก็ตามวิธีที่เร็วที่สุดที่ฉันรู้คือใช้ไลบรารี Express.js กับ body-parser

var express = require("express");
var bodyParser = require("body-parser");
var app = express();

app.use(bodyParser.urlencoded({extended : true}));

app.post("/pathpostdataissentto", function(request, response) {
  console.log(request.body);
  //Or
  console.log(request.body.fieldName);
});

app.listen(8080);

ที่สามารถทำงานกับสตริง แต่ฉันจะเปลี่ยน bodyParser.urlencoded เป็น bodyParser.json แทนหากข้อมูล POST มีอาร์เรย์ JSON

ข้อมูลเพิ่มเติม: http://www.kompulsa.com/how-to-accept-and-parse-post-requests-in-node-js/


4

คุณต้องได้รับPOSTข้อมูลเป็นชิ้น ๆ โดยใช้request.on('data', function(chunk) {...})

const http = require('http');

http.createServer((req, res) => {
    if (req.method == 'POST') {
        whole = ''
        req.on('data', (chunk) => {
            # consider adding size limit here
            whole += chunk.toString()
        })

        req.on('end', () => {
            console.log(whole)
            res.writeHead(200, 'OK', {'Content-Type': 'text/html'})
            res.end('Data received.')
        })
    }
}).listen(8080)

คุณควรพิจารณาการเพิ่มขีด จำกัด ของขนาดที่ตำแหน่งที่ระบุเป็นthejh ปัญหา


นี่เป็นสิ่งที่อ่อนแอกว่าการโจมตีแบบลอริสช้าหรือไม่?

Nodejs มีความอ่อนไหวต่อ loris ช้ากว่าเช่น php - เนื่องจากไม่ได้สร้างวัตถุเซสชันขนาดใหญ่รอบการเชื่อมต่อ http ทุกครั้ง อย่างไรก็ตามมันปรากฏรหัสนี้ยังสามารถแนะนำช่องโหว่ loris ช้า สิ่งนี้สามารถป้องกันได้ด้วยการsetTimeoutที่สิ้นสุดการเชื่อมต่อหลังจากช่วงระยะเวลาหนึ่งถ้าไม่ได้รับการร้องขอแบบเต็มภายในหน้าต่างนั้น
Gershom


3

หากคุณใช้Express.jsก่อนที่คุณจะสามารถเข้าถึง req.body คุณต้องเพิ่มมิดเดิลแวร์ bodyParser:

app.use(express.bodyParser());

จากนั้นคุณสามารถขอ

req.body.user

มิดเดิลแวร์ส่วนใหญ่ (เช่น bodyParser) จะไม่รวมกับ Express อีกต่อไปและจะต้องติดตั้งแยกต่างหาก ดูคำตอบจาก @ nikodean2 ด้านบนสำหรับคำตอบปัจจุบันเพิ่มเติม
Jeff Collier

app.use (bodyParser ()); ทำงานได้ แต่ให้ข้อความปฏิเสธข้อผิดพลาดสีแดงกับฉัน
Chris Allinson


1

ฉันพบวิดีโอที่อธิบายเกี่ยวกับวิธีการทำให้สำเร็จ: https://www.youtube.com/watch?v=nuw48-u3Yrg

มันใช้โมดูล "http" เริ่มต้นพร้อมกับโมดูล "querystring" และ "stringbuilder" แอปพลิเคชันใช้ตัวเลขสองตัว (โดยใช้สองช่องข้อความ) จากหน้าเว็บและเมื่อส่งจะส่งคืนผลรวมของทั้งสองนั้น (รวมถึงการยืนยันค่าในกล่องข้อความ) นี่คือตัวอย่างที่ดีที่สุดที่ฉันสามารถหาได้จากที่อื่น

รหัสแหล่งที่เกี่ยวข้อง:

var http = require("http");
var qs = require("querystring");
var StringBuilder = require("stringbuilder");

var port = 9000;

function getCalcHtml(req, resp, data) {
    var sb = new StringBuilder({ newline: "\r\n" });
    sb.appendLine("<html>");
    sb.appendLine(" <body>");
    sb.appendLine("     <form method='post'>");
    sb.appendLine("         <table>");
    sb.appendLine("             <tr>");
    sb.appendLine("                 <td>Enter First No: </td>");

    if (data && data.txtFirstNo) {
        sb.appendLine("                 <td><input type='text' id='txtFirstNo' name='txtFirstNo' value='{0}'/></td>", data.txtFirstNo);
    }
    else {
        sb.appendLine("                 <td><input type='text' id='txtFirstNo' name='txtFirstNo' /></td>");
    }

    sb.appendLine("             </tr>");
    sb.appendLine("             <tr>");
    sb.appendLine("                 <td>Enter Second No: </td>");

    if (data && data.txtSecondNo) {
        sb.appendLine("                 <td><input type='text' id='txtSecondNo' name='txtSecondNo' value='{0}'/></td>", data.txtSecondNo);
    }
    else {
        sb.appendLine("                 <td><input type='text' id='txtSecondNo' name='txtSecondNo' /></td>");
    }

    sb.appendLine("             </tr>");
    sb.appendLine("             <tr>");
    sb.appendLine("                 <td><input type='submit' value='Calculate' /></td>");
    sb.appendLine("             </tr>");

    if (data && data.txtFirstNo && data.txtSecondNo) {
        var sum = parseInt(data.txtFirstNo) + parseInt(data.txtSecondNo);
        sb.appendLine("             <tr>");
        sb.appendLine("                 <td>Sum: {0}</td>", sum);
        sb.appendLine("             </tr>");
    }

    sb.appendLine("         </table>");
    sb.appendLine("     </form>")
    sb.appendLine(" </body>");
    sb.appendLine("</html>");
    sb.build(function (err, result) {
        resp.write(result);
        resp.end();
    });
}

function getCalcForm(req, resp, data) {
    resp.writeHead(200, { "Content-Type": "text/html" });
    getCalcHtml(req, resp, data);
}

function getHome(req, resp) {
    resp.writeHead(200, { "Content-Type": "text/html" });
    resp.write("<html><html><head><title>Home</title></head><body>Want to some calculation? Click <a href='/calc'>here</a></body></html>");
    resp.end();
}

function get404(req, resp) {
    resp.writeHead(404, "Resource Not Found", { "Content-Type": "text/html" });
    resp.write("<html><html><head><title>404</title></head><body>404: Resource not found. Go to <a href='/'>Home</a></body></html>");
    resp.end();
}

function get405(req, resp) {
    resp.writeHead(405, "Method not supported", { "Content-Type": "text/html" });
    resp.write("<html><html><head><title>405</title></head><body>405: Method not supported</body></html>");
    resp.end();
}

http.createServer(function (req, resp) {
    switch (req.method) {
        case "GET":
            if (req.url === "/") {
                getHome(req, resp);
            }
            else if (req.url === "/calc") {
                getCalcForm(req, resp);
            }
            else {
                get404(req, resp);
            }
            break;
        case "POST":
            if (req.url === "/calc") {
                var reqBody = '';
                req.on('data', function (data) {
                    reqBody += data;
                    if (reqBody.length > 1e7) { //10MB
                        resp.writeHead(413, 'Request Entity Too Large', { 'Content-Type': 'text/html' });
                        resp.end('<!doctype html><html><head><title>413</title></head><body>413: Request Entity Too Large</body></html>');
                    }
                });
                req.on('end', function () {
                    var formData = qs.parse(reqBody);
                    getCalcForm(req, resp, formData);
                });
            }
            else {
                get404(req, resp);
            }
            break;
        default:
            get405(req, resp);
            break;
    }
}).listen(port);

1

สำหรับผู้ที่ใช้การอัปโหลด POST ไบนารีแบบดิบโดยไม่ต้องเข้ารหัสโอเวอร์เฮดคุณสามารถใช้:

ลูกค้า:

var xhr = new XMLHttpRequest();
xhr.open("POST", "/api/upload", true);
var blob = new Uint8Array([65,72,79,74]); // or e.g. recorder.getBlob()
xhr.send(blob);

เซิร์ฟเวอร์:

var express = require('express');
var router = express.Router();
var fs = require('fs');

router.use (function(req, res, next) {
  var data='';
  req.setEncoding('binary');
  req.on('data', function(chunk) {
    data += chunk;
  });

  req.on('end', function() {
    req.body = data;
    next();
  });
});

router.post('/api/upload', function(req, res, next) {
  fs.writeFile("binaryFile.png", req.body, 'binary', function(err) {
    res.send("Binary POST successful!");
  });
});

1

คุณสามารถใช้มิดเดิลแวร์ด่วนซึ่งตอนนี้มีตัวแยกวิเคราะห์ตัวอยู่ภายใน นี่หมายความว่าคุณต้องทำสิ่งต่อไปนี้:

import express from 'express'

const app = express()

app.use(express.json())

app.post('/thing', (req, res) => {
  console.log(req.body) // <-- this will access the body of the post
  res.sendStatus(200)
})

ตัวอย่างรหัสนั้นคือ ES6 ที่มี Express 4.16.x


0

คุณสามารถแยกพารามิเตอร์โพสต์โดยไม่ต้องใช้ด่วน

1: nmp install multiparty

2: นำเข้าหลายส่วน เช่นvar multiparty = require('multiparty');

3: `

if(req.method ==='POST'){
   var form = new multiparty.Form();
   form.parse(req, function(err, fields, files) {
      console.log(fields['userfile1'][0]);
    });
    }

4: และรูปแบบ HTML คือ

<form method=POST enctype=multipart/form-data>
<input type=text name=userfile1><br>
<input type=submit>
</form>

ฉันหวังว่าสิ่งนี้จะได้ผลสำหรับคุณ ขอบคุณ


0

ขนาด จำกัด POST หลีกเลี่ยงการทำให้แอปโหนดของคุณท่วม มีโมดูลตัวถังขนาดใหญ่ที่เหมาะสำหรับทั้งการเชื่อมต่อและด่วนที่สามารถช่วยคุณ จำกัด การร้องขอตามขนาดและความยาว



0

ในเขตข้อมูลแบบฟอร์มเช่นนี้

   <input type="text" name="user[name]" value="MyName">
   <input type="text" name="user[email]" value="myemail@somewherefarfar.com">

คำตอบข้างต้นบางส่วนจะล้มเหลวเพราะรองรับเฉพาะข้อมูลที่มีการ จำกัด เท่านั้น

ตอนนี้ฉันใช้คำตอบ Casey Chu แต่ใช้คำสั่ง"qs"แทนโมดูล "querystring" นี่คือโมดูล"body-parser" ที่ใช้เช่นกัน ดังนั้นหากคุณต้องการข้อมูลซ้อนคุณต้องติดตั้ง qs

npm install qs --save

จากนั้นแทนที่บรรทัดแรกเช่น:

//var qs = require('querystring');
var qs = require('qs'); 

function (request, response) {
    if (request.method == 'POST') {
        var body = '';

        request.on('data', function (data) {
            body += data;

            // Too much POST data, kill the connection!
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6)
                request.connection.destroy();
        });

        request.on('end', function () {
            var post = qs.parse(body);
            console.log(post.user.name); // should work
            // use post['blah'], etc.
        });
    }
}

0

คุณสามารถส่งและรับคำขอ POST ได้ง่าย ๆ โดยใช้ "คำขอ - ไคลเอนต์ HTTP แบบง่าย" และสัญญา Javascript

var request = require('request');

function getData() {
    var options = {
        url: 'https://example.com',
        headers: {
            'Content-Type': 'application/json'
        }
    };

    return new Promise(function (resolve, reject) {
        var responseData;
        var req = request.post(options, (err, res, body) => {
            if (err) {
                console.log(err);
                reject(err);
            } else {
                console.log("Responce Data", JSON.parse(body));
                responseData = body;
                resolve(responseData);
            }
        });
    });
}

0

คุณจำเป็นต้องใช้ bodyParser () ถ้าคุณต้องการให้ข้อมูลในแบบฟอร์มสามารถใช้ได้ใน req.body body-parser แยกวิเคราะห์คำขอของคุณและแปลงเป็นรูปแบบที่คุณสามารถดึงข้อมูลที่เกี่ยวข้องที่คุณอาจต้องการได้อย่างง่ายดาย

ตัวอย่างเช่นสมมติว่าคุณมีแบบฟอร์มลงทะเบียนที่ส่วนหน้าของคุณ คุณกำลังกรอกข้อมูลและขอให้เซิร์ฟเวอร์บันทึกรายละเอียดที่อื่น

การแยกชื่อผู้ใช้และรหัสผ่านออกจากคำขอของคุณนั้นง่ายมากหากคุณใช้ body-parser

............................................................

var loginDetails = {

username : request.body.username,

password : request.body.password

};

0

ซับในเดียวที่ไม่มี MIDDLEWARE
หากคุณโพสต์ข้อมูลต่อไปนี้
'name':'ABC'
คุณสามารถแยกวิเคราะห์ได้โดยใช้ซับต่อไปนี้

require('url').parse(req.url, true).query.name
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.