搜尋

首頁  >  問答  >  主體

node.js - Node+express项目,提交表单信息时Cannot read property '_id' of undefined

前言

这是我在学习imooc上node实战时遇到的问题,视频中老师用了以下代码

var app = express()
var express = require('express')

app.use(express.bodyParser())

最后在视频中运行无误。

已解决的问题

我已经知道express.bodyParser()在新版本中被取消

也知道了替代方案中的extend:true的作用

仍然存在的问题

可是当我把代码修正过来之后,仍然报错

修改的代码

var bodyParser = require('body-parser')

app.use(bodyParser.urlencoded({ extended: true }))//将表单数据格式化

报错

^[{ [ValidationError: Movie validation failed]
  message: 'Movie validation failed',
  name: 'ValidationError',
  errors: 
   { year: 
      { [CastError: Cast to Number failed for value "2015/12/31" at path "year"]
        message: 'Cast to Number failed for value "2015/12/31" at path "year"',
        name: 'CastError',
        kind: 'Number',
        value: '2015/12/31',
        path: 'year',
        reason: undefined } } }
/Users/Vagor/Desktop/easy_movie/app.js:123
      res.redirect('/movie/' + movie._id)
                                    ^

TypeError: Cannot read property '_id' of undefined
    at /Users/Vagor/Desktop/easy_movie/app.js:123:37
    at /Users/Vagor/Desktop/easy_movie/node_modules/mongoose/lib/document.js:1747:19
    at handleError (/Users/Vagor/Desktop/easy_movie/node_modules/hooks-fixed/hooks.js:40:22)
    at _next (/Users/Vagor/Desktop/easy_movie/node_modules/hooks-fixed/hooks.js:46:22)
    at fnWrapper (/Users/Vagor/Desktop/easy_movie/node_modules/hooks-fixed/hooks.js:186:18)
    at /Users/Vagor/Desktop/easy_movie/node_modules/mongoose/lib/schema.js:234:13
    at complete (/Users/Vagor/Desktop/easy_movie/node_modules/mongoose/lib/document.js:1131:7)
    at /Users/Vagor/Desktop/easy_movie/node_modules/mongoose/lib/document.js:1160:20
    at ObjectId.SchemaType.doValidate (/Users/Vagor/Desktop/easy_movie/node_modules/mongoose/lib/schematype.js:654:22)
    at /Users/Vagor/Desktop/easy_movie/node_modules/mongoose/lib/document.js:1156:9
    at nextTickCallbackWith0Args (node.js:433:9)
    at process._tickCallback (node.js:362:13)

出错的区块代码

app.post('/admin/movie/new', function(req, res) {
  var id = req.body.movie._id
  var movieObj = req.body.movie
  var _movie
 
  if (id !== 'undefined') {
    Movie.findById(id, function(err, movie) {
      if (err) {
        console.log(err)
      }
 
      _movie = _.extend(movie, movieObj)
      _movie.save(function(err, movie) {
        if (err) {
          console.log(err)
        }
 
        res.redirect('/movie/' + movie._id)
      })
    })
  }
  else {
    _movie = new Movie({
      doctor: movieObj.doctor,
      title: movieObj.title,
      country: movieObj.country,
      language: movieObj.language,
      year: movieObj.year,
      poster: movieObj.poster,
      summary: movieObj.summary,
      flash: movieObj.flash
    })
 
    _movie.save(function(err, movie) {
      if (err) {
        console.log(err)
      }
 
      res.redirect('/movie/' + movie._id)
    })
  }
})

整个app.js代码

var express = require('express')
var port = 3000
var path = require('path')
var bodyParser = require('body-parser')
var _ = require('underscore')
var mongoose = require('mongoose')
var Movie = require('./models/movie.js')
var app = express()


mongoose.connect('mongodb://localhost/imooc')

app.set('views','./views/pages')
app.set('view engine','jade')
// app.use(express.bodyParser())
// app.use(bodyParser.urlencoded())
app.use(bodyParser.urlencoded({ extended: true }))//将表单数据格式化
app.use(express.static(path.join(__dirname,'bower_components')))//告诉浏览器请求样式就到此文件夹查找,dirname就是当前目录
app.listen(port)
app.locals.moment = require('moment')

console.log('imooc started on port:' + port)

//index page
app.get('/',function(req,res){
    Movie.fetch(function(err,movies){
        if (err) {
            console.log(err)
        }
    
        res.render('index',{
            title:'imovie 首页',
            movies:movies
        })
    })
})

//detail page
app.get('/movie/:id',function(req,res){
    var id = req.params.id

    Movie.findById(id, function(err,movie){
        if (err) {
            console.log(err)
        }
        res.render('detail',{
            title:'imovie' + movie.title,
            movie:movie
        })
    })
    
})

//admin page
app.get('/admin/movie',function(req,res){
    res.render('admin',{
        title:'imovie 后台录入页',
        movie:{
            title: '',
            doctor: '',
            country: '',
            year: '',
            language: '',
            summary: '',
            poster: '',
            flash: ''
        }
    })
})
//admin update movie
app.get('/admin/update/:id',function(req,res){
    var id = req.params.id

    if (id) {
        Movie.findById(id,function(err,movie){
            res.render('admin',{
                title:'imovie 后台更新页',
                movie:movie
            })
        })
    }
})
//admin post movie
// admin post movie
app.post('/admin/movie/new', function(req, res) {
  var id = req.body.movie._id
  var movieObj = req.body.movie
  var _movie
 
  if (id !== 'undefined') {
    Movie.findById(id, function(err, movie) {
      if (err) {
        console.log(err)
      }
 
      _movie = _.extend(movie, movieObj)
      _movie.save(function(err, movie) {
        if (err) {
          console.log(err)
        }
 
        res.redirect('/movie/' + movie._id)
      })
    })
  }
  else {
    _movie = new Movie({
      doctor: movieObj.doctor,
      title: movieObj.title,
      country: movieObj.country,
      language: movieObj.language,
      year: movieObj.year,
      poster: movieObj.poster,
      summary: movieObj.summary,
      flash: movieObj.flash
    })
 
    _movie.save(function(err, movie) {
      if (err) {
        console.log(err)
      }
 
      res.redirect('/movie/' + movie._id)
    })
  }
})

//list page
app.get('/admin/list',function(req,res){
    Movie.fetch(function(err,movies){
        if (err) {
            console.log(err)
        }

        res.render('list',{
            title:'imovie 列表页',
            movies:movies
        })
    })
})

//list delete movie
app.delete('/admin/list',function(req,res){
    var id = req.query.id

    if (id) {
        Movie.remove({_id:id},function(err,movie){
            if (err) {
            console.log(err)
            }

            else{
                res.json({success:1})
            }
        })
    };
})

情各位指出错误的根源并指正,谢谢!

问题休正及补充

当我submit(post方式)表单数据为数字时,可以提交并返回,但仍有文件传输错误。

但是当我提交的是字符串(或者说是中文时,我不知道是什么原因),就会产生上述错误,服务器被强制关闭

我已经将代码上传至github,希望各位能帮我查看一下问题

大家讲道理大家讲道理2784 天前626

全部回覆(8)我來回復

  • 巴扎黑

    巴扎黑2017-04-17 13:48:05

    除了bodyParser(urlencoded()),還需要一個bodyParser(json()),把Express升級到4.x使用生成器產生一個專案就知道了。

    回覆
    0
  • 怪我咯

    怪我咯2017-04-17 13:48:05

    看了下程式碼邏輯上沒有問題,但是缺少安全驗證.主要問題是你發送請求的id不對啊,正確的Object_id的格式是24個字符的16進制數,例如:568761de48b492fd35046a45.程式崩潰的原因就是沒有做url網址列的校驗.因為在正常情況下,客戶端傳遞的id參數是從後台獲取的ObjectId,但是為了嚴謹性現在做以下處理:

     var id = req.params.id;
    
     if (id.match(/^[0-9a-fA-F]{24}$/)) {
       Notice.findById(id, function(err, notice) {
         if (err) {
           res.json({
             no: 0,
             msg: '获取失败:' + err
           });
         } else {
           var result = {
             no: 1
           };
           result.obj = notice;
           res.json(result);
         }
       });
     } else {
       res.json({
         error: true,
         msg: id + '不存在'
       });
     }

    回覆
    0
  • 怪我咯

    怪我咯2017-04-17 13:48:05

    遇到一模一樣的問題了,請問你是怎麼解決啊,困擾我兩天了

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 13:48:05

    樓主報的錯是 [{ [ValidationError: Movie validation failed],傳入的資料跟沒沒有通過 Movie 的屬性驗證。

    樓主在寫路由的時候,如果有 err,請務必使用 return,例如樓主 _movie.save(),需要寫成下面的形式,否則出現錯誤會把自己看懵掉。

    _movie.save(function(err, movie) {
        if (err) return console.log(err);
    
        //    ...
    });

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 13:48:05

    mogoose的 model.save(function(err){}) 的回呼參數只有 err 一個吧

    http://mongoosejs.com/docs/models.html Constructing documents這一節

    _id在new的時候已經生成了。
    所以寫成下面這樣:

    _movie.save(function(err) {
      if (err) {
        console.log(err)
        // 这边应该跳转至错误页面
        return res.redirect('/some/error/handler/page/' + err + JSON. stringify(_movie));
      }
    
      res.redirect('/movie/' + _movie._id);
    })

    回覆
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 13:48:05

    不知道題主解決問題了沒~
    我也遇到了相同的問題。
    不過最後發現是admin.jade的縮排有問題
    如果題主還沒解決問題的話可以試試看(●'◡'●)

    回覆
    0
  • 高洛峰

    高洛峰2017-04-17 13:48:05

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

    回覆
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 13:48:05

    其實你可以不用急著貼一大堆程式碼,先追蹤下你的資料就知道哪裡有問題了。錯誤提示很明顯是你用的東西沒有_id這個字段,那你就查看下你目前用的東西到底是什麼就可以了。當資料從資料庫出來就開始追踪,控制台輸出看下資料結構和型別。然後每次對資料有操作都看一下資料的結構和類型是否改變了。最後只要追蹤到你出問題的地方就可以了,看看輸出的到底是不是你想要的東西。

    回覆
    0
  • 取消回覆