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

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

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

问题

  1. 我需要更改哪些表单数据才能到达后端 适当吗?
  2. 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

【问题讨论】:

    标签: node.js mongodb angular express mongoose


    【解决方案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 方法一样。

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

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

          3. 现在绑定前端对象。

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

          快乐的结局?

          【讨论】:

            猜你喜欢
            • 2017-08-27
            • 2022-01-26
            • 2018-07-05
            • 2020-09-13
            • 2017-01-14
            • 1970-01-01
            • 1970-01-01
            • 2018-05-14
            • 1970-01-01
            相关资源
            最近更新 更多