Node.js(Angular 4、MongoDB)中POST请求req.body为空问题
我来帮你捋清楚问题根源,其实核心是请求的Content-Type头和实际发送的数据格式不匹配,导致后端的bodyParser无法正确解析参数。
问题原因
你在Angular服务里手动设置了Content-Type: application/x-www-form-urlencoded,但直接传递了一个JavaScript对象task。这种情况下,Angular会默认把对象序列化为JSON格式,但header告诉后端要解析表单格式的数据——后端的bodyParser会根据header选择对应的解析器(urlencoded解析器),但JSON格式的数据它处理不了;而json解析器又因为header不是application/json不会生效,最终就导致req.body是空对象。
至于直接传字符串'test3'能成功,只是因为纯字符串刚好符合x-www-form-urlencoded的简单格式,但这并不是传递结构化数据的正确方式。
解决方案(推荐用JSON格式传递)
JSON是前后端传递结构化数据的标准方式,修改你的Angular服务,去掉手动设置的x-www-form-urlencoded头即可——Angular的HttpClient.post默认会把对象序列化为JSON,并自动设置Content-Type: application/json头:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class RequestService { constructor(private http: HttpClient) { } postTask(task) { // 无需手动设置Content-Type,默认就是application/json return this.http.post('http://localhost:3000/tasks', task); } }
然后修改后端的POST接口,直接使用req.body里的参数创建文档:
app.post('/tasks', function(req, res) { console.log("Here is req2", req.body); var savedata = new Model({ 'taskName': req.body.taskName, // 从req.body获取传递的taskName 'isDone': req.body.isDone || false, 'createdAt': Date.now(), 'prioraty': req.body.prioraty || 'medium' }).save(function (err, result) { if (err) throw err; if (result) { res.json(result) } }) });
如果你一定要用表单格式传递
如果因为某些原因必须使用x-www-form-urlencoded,需要把JavaScript对象转换成表单格式的字符串,比如用URLSearchParams:
import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class RequestService { constructor(private http: HttpClient) { } postTask(task) { const formData = new URLSearchParams(); // 遍历对象,把键值对添加到表单数据中 Object.keys(task).forEach(key => formData.set(key, task[key])); const headers = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }); return this.http.post('http://localhost:3000/tasks', formData.toString(), { headers }); } }
这样后端的bodyParser.urlencoded({ extended: true })就能正确解析req.body了。
内容的提问来源于stack exchange,提问作者Anna F

