【问题标题】:API not accepting data from Form in expressAPI 不接受来自 Express 表单的数据
【发布时间】:2018-09-25 12:37:24
【问题描述】:

我有一个如下的 api,我遇到的问题是,当我使用把手创建一个表单并将表单提交到这个 API 时,我知道它正在访问 api,因为它显示验证消息但它不接受表格中提供的值:

exports.register = function (req, res, next) {
  var username = _.get(req.body, 'username');
  var password = _.get(req.body, 'password');

  if (!username) {
    throw {username: 'This field is required.', status: 400};
  }
  if (!password) {
    throw {password: 'This field is required.', status: 400};
  }

  Users.register(dbUtils.getSession(req), username, password)
    .then(response => writeResponse(res, response, 201))
    .catch(next);
};

所以基本上是一个简单的注册api,表单要求输入用户名和密码,然后点击提交。

以下是我的车把文件的代码:

<div class="row">
    <div class="col-md-6 mx-auto">
        <div class="card card-body">

            <h3 class="text-center">Account Register</h3>
            <form action="/api/v0/register" method="POST" enctype='application/json'>
                <div class="form-group">
                    <label for="name">Name</label>
                    <input type="text" class="form-control" name="username" value="{{name}}" required>
                </div>

                <div class="form-group">
                    <label for="password">Password</label>
                    <input type="password" class="form-control" name="password" value="{{password}}" required>
                </div>


                <button type="submit" class="btn btn-primary">Submit</button>

            </form>
        </div>
    </div>
</div>

当我单击提交时,页面会显示来自我的路由的响应,该用户名是必需的。我很困惑的是为什么路由没有检测到用户名和密码:

消息:

{
"username": "This field is required."
}

我正在使用 Nodejs、express、express 车把。

我的完整app.js如下:

var express = require('express')
  , path = require('path')
  , routes = require('./routes')
  , nconf = require('./config')
  , swaggerJSDoc = require('swagger-jsdoc')
  , methodOverride = require('method-override')
  , errorHandler = require('errorhandler')
  , bodyParser = require('body-parser')
  , setAuthUser = require('./middlewares/setAuthUser')
  , neo4jSessionCleanup = require('./middlewares/neo4jSessionCleanup')
  , writeError = require('./helpers/response').writeError;

  const exphbs = require('express-handlebars');


var app = express()
  , api = express();

app.use(nconf.get('api_path'), api);

// Handlebars middleware
app.engine('handlebars', exphbs({
  defaultLayout: 'main'
}));
app.set('view engine', 'handlebars');

// Body Parser middleware
app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json());

var swaggerDefinition = {
  info: {
    title: 'Neo4j Movie Demo API (Node/Express)',
    version: '1.0.0',
    description: '',
  },
  host: 'localhost:3000',
  basePath: '/',
};

// options for the swagger docs
var options = {
  // import swaggerDefinitions
  swaggerDefinition: swaggerDefinition,
  // path to the API docs
  apis: ['./routes/*.js'],
};

// initialize swagger-jsdoc
var swaggerSpec = swaggerJSDoc(options);

// serve swagger
api.get('/swagger.json', function(req, res) {
  res.setHeader('Content-Type', 'application/json');
  res.send(swaggerSpec);
});

app.use('/docs', express.static(path.join(__dirname, 'swaggerui')));
app.set('port', nconf.get('PORT'));

//api.use(bodyParser.json());
api.use(methodOverride());

//enable CORS
api.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Credentials", "true");
  res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT,DELETE");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
  next();
});

//api custom middlewares:
api.use(setAuthUser);
api.use(neo4jSessionCleanup);


// User Register Route
app.get('/users/register', (req, res) => {

  res.render('users/register');
});

//api routes
api.post('/register', routes.users.register);
api.post('/login', routes.users.login);
api.get('/users/me', routes.users.me);
api.get('/movies', routes.movies.list);
api.get('/movies/recommended', routes.movies.getRecommendedMovies);
api.get('/movies/rated', routes.movies.findMoviesRatedByMe);
api.get('/movies/:id',  routes.movies.findById);
api.get('/movies/genre/:id',  routes.movies.findByGenre);
api.get('/movies/daterange/:start/:end', routes.movies.findMoviesByDateRange);
api.get('/movies/directed_by/:id', routes.movies.findMoviesByDirector);
api.get('/movies/acted_in_by/:id', routes.movies.findMoviesByActor);
api.get('/movies/written_by/:id', routes.movies.findMoviesByWriter);
api.post('/movies/:id/rate', routes.movies.rateMovie);
api.delete('/movies/:id/rate', routes.movies.deleteMovieRating);
api.get('/people', routes.people.list);
api.get('/people/:id', routes.people.findById);
api.get('/people/bacon', routes.people.getBaconPeople);
api.get('/genres', routes.genres.list);

//api error handler
api.use(function(err, req, res, next) {
  if(err && err.status) {
    writeError(res, err);
  }
  else next(err);
});

app.listen(app.get('port'), () => {
  console.log('Express server listening on port ' + app.get('port') + ' see docs at /docs');
});

这是用户用户路由文件:

var Users = require('../models/users')
  , writeResponse = require('../helpers/response').writeResponse
  , writeError = require('../helpers/response').writeError
  , loginRequired = require('../middlewares/loginRequired')
  , dbUtils = require('../neo4j/dbUtils')
  , _ = require('lodash');


exports.register = function (req, res, next) {


  var username = _.get(req.body, 'username');
  var password = _.get(req.body, 'password');

  if (!username) {
    throw {username: 'This field is required.', status: 400};
  }
  if (!password) {
    throw {password: 'This field is required.', status: 400};
  }

  Users.register(dbUtils.getSession(req), username, password)
    .then(response => writeResponse(res, response, 201))
    .catch(next);
};


exports.login = function (req, res, next) {
  var username = _.get(req.body, 'username');
  var password = _.get(req.body, 'password');

  if (!username) {
    throw {username: 'This field is required.', status: 400};
  }
  if (!password) {
    throw {password: 'This field is required.', status: 400};
  }

  Users.login(dbUtils.getSession(req), username, password)
    .then(response => writeResponse(res, response))
    .catch(next);
};


exports.me = function (req, res, next) {
  loginRequired(req, res, () => {
    var authHeader = req.headers['authorization'];
    var match = authHeader.match(/^Token (\S+)/);
    if (!match || !match[1]) {
      throw {message: 'invalid authorization format. Follow `Token <token>`', status: 401};
    }

    var token = match[1];
    Users.me(dbUtils.getSession(req), token)
      .then(response => writeResponse(res, response))
      .catch(next);
  })
};

这是我的用户模型文件:

"use strict"

var uuid = require('node-uuid');
var randomstring = require("randomstring");
var _ = require('lodash');
var dbUtils = require('../neo4j/dbUtils');
var User = require('../models/neo4j/user');
var crypto = require('crypto');

var register = function (session, username, password) {
  return session.run('MATCH (user:User {username: {username}}) RETURN user', {username: username})
    .then(results => {
      if (!_.isEmpty(results.records)) {
        throw {username: 'username already in use', status: 400}
      }
      else {
        return session.run('CREATE (user:User {id: {id}, username: {username}, password: {password}, api_key: {api_key}}) RETURN user',
          {
            id: uuid.v4(),
            username: username,
            password: hashPassword(username, password),
            api_key: randomstring.generate({
              length: 20,
              charset: 'hex'
            })
          }
        ).then(results => {
            return new User(results.records[0].get('user'));
          }
        )
      }
    });
};

var me = function (session, apiKey) {
  return session.run('MATCH (user:User {api_key: {api_key}}) RETURN user', {api_key: apiKey})
    .then(results => {
      if (_.isEmpty(results.records)) {
        throw {message: 'invalid authorization key', status: 401};
      }
      return new User(results.records[0].get('user'));
    });
};

var login = function (session, username, password) {
  return session.run('MATCH (user:User {username: {username}}) RETURN user', {username: username})
    .then(results => {
        if (_.isEmpty(results.records)) {
          throw {username: 'username does not exist', status: 400}
        }
        else {
          var dbUser = _.get(results.records[0].get('user'), 'properties');
          if (dbUser.password != hashPassword(username, password)) {
            throw {password: 'wrong password', status: 400}
          }
          return {token: _.get(dbUser, 'api_key')};
        }
      }
    );
};

function hashPassword(username, password) {
  var s = username + ':' + password;
  return crypto.createHash('sha256').update(s).digest('hex');
}

module.exports = {
  register: register,
  me: me,
  login: login
};

我也尝试过 console.log req.body.username,但由于某种原因它未定义。

【问题讨论】:

  • 您必须显示更多您的快速代码。另外,你为什么要使用_.get() 来访问一个简单的属性?您是否安装了表单处理中间件?导出的函数是怎么调用的?
  • 我实际上是在使用来自 neo4j 图形数据库的示例项目。我以
    的形式调用 register api 我没有这样的中间件。
  • 嗯,您需要中间件来将表单提交解析为req.body 对象。这不会自动发生。
  • 你能举个例子吗?
  • 现在您已经展示了您的快速代码,您已经安装了 body-parser 中间件。我不知道为什么您的表单提交不起作用。

标签: node.js express handlebars.js


【解决方案1】:

您的中间件:

// Body Parser middleware
app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json());

需要在您将api 路由器插入路由链之前。正如您现在所拥有的,请求被路由到您的 api 路由器,而无需执行此中间件。

所以,应该是这样的:

// Body Parser middleware
// must come before any requests, middleware or routers that want to use
// the body-parser middleware results
app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json());

app.use(nconf.get('api_path'), api);

另外,改变这个:

, api = express();

到:

, api = express.Router();

所以您只是使用路由器而不是应用程序对象。 app 对象也是一个路由器,但是你真正想要的是一个普通的路由器。

【讨论】:

  • @AminBaig - 数据库代码问题将是一个新问题。如果您无法解决这个问题,我建议您提出一个关注细节的新问题。我不知道你的数据库,所以我真的帮不上忙。
猜你喜欢
  • 2018-11-08
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 2016-02-11
相关资源
最近更新 更多