填坑笔记—Nodejs获取form-data数据

本篇讲解如何在后台解决获取formData数据的问题

问题描述

原本的要练习cookie-session登陆的方法,顺便想要使用一下原生的xhr对象,却发现了问题,使用原生xhr对象发送post请求时,我将要发送的数据放入formData中并在后台接收,这里formData是XMLHttpRequest 2.0的新的数据类型:

XMLHttpRequest Level 2添加了一个新的接口FormData. 利用FormData对象,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()方法来异步的提交这个”表单”。比起普通的ajax, 使用FormData的最大优点就是我们可以异步上传一个二进制文件。

刚开始就出错了:

前端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<script>
function register() {
const username = document.getElementById('username').value;
const psw = document.getElementById('psw').value;
let formData = new FormData();
formData.append('username', username);
formData.append('psw', psw);
console.log(formData);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("Response was unsuccessful:" + xhr.status);
}
}
};
xhr.open("post", "/register", true);
xhr.send(formData);
}
</script>
</head>
<body>
<div class="main">
用户名:<input type="text" id="username" name="username"/>
密码:<input type="password" id="psw" name="psw"/>
<div class="button">
<button class="btn btn-primary">登陆</button>
<button class="btn btn-primary" onclick="register()">注册</button>
</div>
</div>

想在后台接收formData的数据,返回却是个空对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//后台代码
const path = require('path');
const express = require('express');
const app = new express();
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static('public'));
app.post('/register',(req,res)=>{
console.log(req.body);
res.send("ok");
});
app.listen(3000, () => {
console.log('server started at http://localhost:3000');
});
module.exports = app;

空对象

于是在浏览器查看请求信息,发现formData的数据被放在了Request Payload中:

FormData提交格式的每个数据分三部分:

  • 第一部分也就是第一行,表示“分界线(boundary)”,我尚未深入研究这个分界线,不过,我没估计错的话,二进制大文件分隔传输时候,就是使用这个分界线。在webkit核心中,使用“——WebKitFormBoundary”加16位随机Base64位编码的字符串作为分隔边界。根据Firebug的显示,Firefox中,似乎是使用很多个”-“加时间戳进行边界分隔的。这里的边界的作用比较单纯,可能就是把表单的这两个字段作为两个独立数据流传输。
  • 第二部分也就是第二行,表示内容配置,这里都是统一的form-data(因为是FormData对象格式提交的),然后紧跟着name键值。
  • 第三部分就是第三行,表示传输的值。

那么为什么它会保存在Request Payload中而不是请求信息的body中呢?

因为HTTP POST表单请求提交时,使用的Content-Type是application/x-www-form-urlencoded,而使用原生AJAX的POST请求如果不指定请求头RequestHeader,默认使用的Content-Type是text/plain;charset=UTF-8。Content-Type不是application/x-www-form-urlencoded的POST请求是不会读取请求体数据和进行相应的参数处理的。

解决方案:

1、设置请求的Content-type字段为application/x-www-form-urlencoded

1
2
3
xhr.open("post", "/register", true);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send(formData);

此时在后台可以获取到req.body中的数据。

2、使用express的中间件connect-multiparty ,它是专门处理此类post数据相关的依赖包。
安装依赖以后在服务器端使用:

1
2
3
4
5
6
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
app.post('/register', multipartMiddleware, function(req, res) {
console.log('get FormData Params: ', req.body);
});

如此可以获得formData中的数据:

demo地址:https://github.com/lipeishang/JS-formData