Req.Body 是 Angular 2 表单提交 + Bodyparser 上的空对象

Posted

技术标签:

【中文标题】Req.Body 是 Angular 2 表单提交 + Bodyparser 上的空对象【英文标题】:Req.Body is empty object on Angular 2 Form submission + Bodyparser 【发布时间】:2017-05-18 23:03:52 【问题描述】:

我的应用程序中有一个反应式(模型驱动)表单,我无法将表单数据传递给 mongoose。当我通过 http post 方法提交数据时,我不断收到错误,因为后端正在接收一个空对象。

我知道后端可以正常工作,因为当我使用 Postman 提交帖子请求时,我得到的结果状态为“201 Created”。过去几年我一直在阅读论坛和各种博客几天,我仍然很难过。

问题

    我需要更改哪些表单数据才能到达后端 适当吗? Angular2 表单数据提交是否有最佳实践?

注意事项 看起来可能缺少一些内容,例如 URL,并且您会注意到表单中的一些附加字段。为了简洁起见,我故意不包括所有这些,并混淆了到我的后端的实际链接。

后端 - 猫鼬

jobs.controllers.js

var mongoose = require('mongoose');
var Job = mongoose.model('Job');
module.exports.addNewJob = function(req, res)
  console.log(req.body);//added to see req payload from client
  Job
        .create(
            _id: req.body.jobid,
            desc: req.body.name,
            type: req.body.jobType,
            location: req.body.location
        ,function(err, job)
            if(err)
                console.log("Error creating job");
                res
                    .status(400)
                    .json(err);
            else
                console.log("Job Created", job);
                res
                    .status(201)
                    .json(job);
            
        );

jobs.model.js

var mongoose = require('mongoose');
var jobSchema = new mongoose.Schema(
    _id: 
        type: String
    ,
    desc: 
        type: String
    ,
    type: 
        type: String,
        default: "TM"
    ,
    location: String
);
mongoose.model('Job', jobSchema);

db.js

var mongoose = require ('mongoose');
var dburl = 'mongodb://localhost:27017/dbname';

mongoose.connect(dburl);

mongoose.connection.on('connected', function()
    console.log('Mongoose connected to ' + dburl);
);

mongoose.connection.on('disconnected', function()
    console.log('Mongoose disconnedted');
);

mongoose.connection.on('error', function(err)
    console.log('Mongoose connection error: ' + err);
);

require('./jobs.model.js');

index.js

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

var ctrlJobs = require('../controllers/jobs.controllers.js');

router
    .route('/jobs')
    .get(ctrlJobs.jobsGetAll)
    .post(ctrlJobs.addNewJob);

module.exports = router;

app.js

require('./api/data/db.js');
var express = require('express');
var app = express ();
var path = require('path');
var bodyParser = require('body-parser');

var routes = require('./api/routes');

app.use(function(req, res, next) 
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
);

app.use(express.static(path.join(__dirname, 'public')));

app.use(bodyParser.urlencoded(extended: false));

app.use('/api', routes);//Goes to index.js

前端 - Angular2 最终

jobs.service

import  Injectable  from '@angular/core';
import  Http, Response, Headers, RequestOptions  from '@angular/http';

import  Observable  from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';


@Injectable()
export class JobsService
    private _url = "http://123.456.789.100/api/jobs"; //removed actual address for post
    constructor(private _http: Http)

    addNewJob(form: Object)
        let headers = new Headers('Content-Type':'application/json');
        let options = new RequestOptions(headers: headers);
        return this._http
                .post(this._url, JSON.stringify(form), options)
                .map(this.extractData)
                .catch(this.handleError);
    

    private extractData(res: Response)
        let body = res.json();
        return body.data ||  ;
    

    private handleError (error: Response | any) 
    let errMsg: string;
    if (error instanceof Response) 
      const body = error.json() || '';
      const err = body.error || JSON.stringify(body);
      errMsg = `$error.status - $error.statusText || '' $err`;
     else 
      errMsg = error.message ? error.message : error.toString();
    
    console.error(errMsg);
    return Observable.throw(errMsg);
  

job-form.component

import  Component, OnInit  from '@angular/core';
import  FormBuilder, FormGroup, Validators  from '@angular/forms';
import  Router, ActivatedRoute  from '@angular/router';

import  JobsService  from './jobs.service';

@Component(
    templateUrl: './job-form.component.html',
    providers: [JobsService]
)

export class JobFormComponent implements OnInit 

    id: string;
    job: any;
    jobForm: FormGroup;
    title: string;

    constructor(
        private _fb: FormBuilder,
        private _router: Router,
        private _route: ActivatedRoute,
        private _jobsService: JobsService
        )

        


    ngOnInit(): void 
        this.jobForm = this._fb.group(
                jobid: ['', Validators.required],
                name: ['', Validators.required],
                jobType: ['', Validators.required],
                location: ['', Validators.required]
            );

        this.id = this._route.snapshot.params['id'];

        this.title = this.id ? "Edit Job" : "Create New Job";

    

    save(form: any)
        console.log(this.jobForm.value);

        this._jobsService.addNewJob(form).subscribe((dataResponse) => 
            console.log("Submitting" + dataResponse);
        );
    
    reset()
        this.jobForm.reset();
    

job-form.component.html

<form [formGroup]="jobForm" novalidate (ngSubmit)="save(jobForm.value)">
                <div class="row">
                    <div class="col-xs-2">
                        <label>Job Number</label>
                        <input [ngModel]="job?.jobid ? job.jobid : ''" class="form-control" type="text" formControlName="jobid">
                    </div>
                    <div class="col-xs-8">
                        <label>Title</label>
                        <input [ngModel]="job?.name ? job.name : ''" class="form-control" type="text" formControlName="name">
                    </div>
                    <div class="col-xs-2">
                        <label>Type</label><br />
                        <select [ngModel]="job?.jobType ? job.jobType : ''"class="form-control" formControlName="jobType">
                            <option value="TM">T&M</option>
                            <option value="LS">Lump Sum</option>
                        </select>
                    </div>
                </div>
                <div class="row">
                    <div class="col-xs-2">
                        <label>Status</label><br />
                        <select class="form-control" formControlName="status" [ngModel]="job?.status ? job.status : ''">
                            <option value="Pending">Pending</option>
                            <option value="Active">Active</option>
                            <option value="On Hold">On Hold</option>
                            <option value="Complete">Complete</option>
                            <option value="Closed">Closed</option>
                        </select>
                    </div>
                    <div class="col-xs-5">
                        <label>Location</label>
                        <input [ngModel]="job?.location ? job.location : ''" class="form-control" type="text" formControlName="location">
                    </div>
                </div>
               <br />
                <div class="row">
                    <div class="col-xs-1">
                        <button type="btn btn-primary" class="btn btn-primary" [disabled]="!jobForm.valid">Submit</button>
                    </div>
                    <div class="col-xs-1">
                        <button class="btn btn-default" (click)="reset()">Reset</button>
                    </div>
                </div>
            </form>

测试

将 headers 设置为 application/json,req.body 是一个空对象


当我将标题设置为 application/x-www-form-urlencoded 时,req.body 显示

 '"jobid":"8746541","name":"asdfasdfasdfasdf","jobType":"LS","location":"asdfa"':''

提交时 XHR

邮递员Success

【问题讨论】:

【参考方案1】:

在文件 jobs.service 中,您将 Header 设置为

'Content-Type':'application/json'

在 index.js 文件中,您正在处理正文请求

app.use(bodyParser.urlencoded(extended: false));

所以你可以做两种解决方案。

1.) 在 jobs.service 中进行更改

'Content-Type': 'application/x-www-form-urlencoded'

2.) 或更改 index.js

app.use(bodyParser.json());

【讨论】:

【参考方案2】:

解决方案

将行 app.use(bodyParser.json()); 添加到 app.js。本质上,这告诉应用程序它应该原生地理解 JSON。现在在应用程序中提交表单会导致将新记录添加到 mongodb。

【讨论】:

【参考方案3】:

在 app.js 中添加以下中间件...

app.use(bodyParser.json());
app.use(bodyParser.urlencoded(extended: true));

欲了解更多信息,请访问此网站:link!

【讨论】:

【参考方案4】:

1.在前端级别:- 使用反应驱动形式时 通过前端类文件绑定 对象作为 getRawValue()。

1.1 前端到后端的集成 例如我们确定的服务 调用方法时我们必须通过 保存时绑定的对象包括 headers 就像它是 post 方法一样。

    通过要求 bodyparser 添加中间件。将 use 用作 bodyparser.json。

    在邮递员中导航到特定路线,首先检查新数据并发布。

    现在绑定前端对象。

    我们传递给 post rest API 方法的是来自前端的对象。

快乐的结局?

【讨论】:

以上是关于Req.Body 是 Angular 2 表单提交 + Bodyparser 上的空对象的主要内容,如果未能解决你的问题,请参考以下文章

req.body 未定义并使用 Angular 进行快速 API 测试

使用 http 时,req.body 为空 。在 angular 和 node.js 中发布

Angular2 http.post 和未定义的 req.body

删除时为空(req.body)(角度)

在邮递员中使用表单数据使 req.body 为空

Angular 2 提交时触发表单验证