405(不允许)〜Vue.js〜Nginx〜Axios〜SQLite〜Express〜

时间:2019-10-07 09:45:06

标签: sqlite express vue.js nginx axios

我有一个简单的应用程序,可以将用户登录并注册到SQLite数据库,该应用程序在localhost上可以很好地工作,但是不能使其在部署中正常工作。它返回错误405 (Not Allowed)Error: Request failed with status code 405。我的服务器是运行Nginx的Ubuntu。

我用于处理登录/注册行为的操作(使用Vuex):

actions: {
    // Login user action.
    login({ commit }, user) {
      // Use Promise object to return desired objects.
      return new Promise((resolve, reject) => {
        commit("auth_request"); // Vuex helper to trigger mutations.

        // Make a call to the server's login and return necessary data.
        axios({
          url: "http://localhost:3000/login", // Uncomment for localhost.
          // url: "http://XX.XX.XX.XX/login", // Uncomment for deployment.
          data: user,
          method: "POST"
        })
          // Fetch necessary data from response.
          .then(resp => {
            // Necessary data.
            const token = resp.data.token;
            const user = resp.data.user;

            localStorage.setItem("token", token); // Store token on localStorage.
            axios.defaults.headers.common["Authorization"] = token; // Set Axio's header.

            commit("auth_success", token, user); // Vuex helper to trigger mutations, which passes JWT token and user data.
            resolve(resp); // Return Promise object that is resolved with a given value.
          })
          // Catch errors.
          .catch(err => {
            commit("auth_error"); // Vuex helper to trigger mutations.
            localStorage.removeItem("token"); // Remove JWT token from the localStorage.
            reject(err); // Return Promise object that is rejected with a given reason.
          });
      });
    },
    // Register user action.
    register({ commit }, user) {
      // Use Promise to return desired objects.
      return new Promise((resolve, reject) => {
        commit("auth_request"); // Vuex helper to trigger mutations.

        // Make a call to the server's register and return necessary data.
        axios({
          url: "http://localhost:3000/register", // Uncomment for localhost.
          // url: "http://XX.XX.XX.XX/register", // Uncomment for deployment.
          data: user,
          method: "POST"
        })
          // Fetch necessary data from response.
          .then(resp => {
            // Necessary data.
            const token = resp.data.token;
            const user = resp.data.user;

            localStorage.setItem("token", token); // Store token on localStorage.
            axios.defaults.headers.common["Authorization"] = token; // Set Axio's header.

            commit("auth_success", token, user); // Vuex helper to trigger mutations, which passes JWT token and user data.
            resolve(resp); // Return Promise that is resolved with a given value.
          })
          // Catch errors.
          .catch(err => {
            commit("auth_error", err); // Vuex helper to trigger mutations.
            localStorage.removeItem("token"); // Remove JWT token from the localStorage.
            reject(err); // Return Promise object that is rejected with a given reason.
          });
      });
    },

对于后端,我使用以下方式通过路由注册启用所有必需的HTTP标头:

#!/usr/bin/env node

"use strict";
const express = require("express");
const DB = require("./db");
const config = require("./config");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const bodyParser = require("body-parser");

// Create required database, Express server and routing.
const db = new DB("sqlitedb");
const app = express();
const router = express.Router();
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());

// CORS middleware configuration to avoid cross origin resource errors.
const allowCrossDomain = function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "*");
  res.header("Access-Control-Allow-Headers", "*");
  next();
};
app.use(allowCrossDomain);

// Route for new users registration.
router.post("/register", function(req, res) {
  // Pass request body to database method and callback function to handle the response.
  db.insert([req.body.email, bcrypt.hashSync(req.body.password, 8)], function(
    err
  ) {
    if (err)
      return res.status(500).send("There was a problem registering the user.");
    db.selectByEmail(req.body.email, (err, user) => {
      if (err) return res.status(500).send("There was a problem getting user");

      // User successfully registered, create an authentication token (JWT).
      let token = jwt.sign({ id: user.id }, config.secret, {
        expiresIn: 86400 // 24 hours expiration time.
      });
      res.status(200).send({ auth: true, token: token, user: user }); // Send 200 HTTP "OK" response, user successfully registered.
    });
  });
});

// Route for users login.
router.post("/login", (req, res) => {
  db.selectByEmail(req.body.email, (err, user) => {
    if (err) return res.status(500).send("Error on the server."); // Some kind of server error.
    if (!user) return res.status(404).send("No user found."); // User not found.

    // Check if given password mathces password in a database.
    let passwordIsValid = bcrypt.compareSync(req.body.password, user.user_pass);
    if (!passwordIsValid)
      return res.status(401).send({ auth: false, token: null }); // Password doesn't match, don't sign in user.

    // Password matches, sign in user.
    let token = jwt.sign({ id: user.id }, config.secret, {
      expiresIn: 86400 // 24 hours expiration time.
    });
    res.status(200).send({ auth: true, token: token, user: user }); // Send 200 (OK) HTTP response, user successfully logged in.
  });
});

app.use(router); // Make the application accessible.

let port = process.env.PORT || 3000; // Dynamically generated port by hosting system or on localhost it's 3000.

app.listen(port, function() {
  console.log("Express server listening on port " + port);
});

我用于处理此应用程序的nginx.conf文件如下(它是HTTP,而不是HTTPS):

server {
        listen 80;
        listen [::]:80;

        root /var/www/html;

        index index.html;

        server_name XX.XX.XX.XX;

        location / {
            try_files $uri $uri/ /index.html;
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Methods *;
            add_header Access-Control-Allow-Headers *;
     }
}

有或没有这些标头(在nginx.conf中)都不会更改行为。我猜这是某种服务器端配置错误,因为正如localhost所说,一切工作都很好。有什么我想念的吗?对于部署,我将取消对url: "http://XX.XX.XX.XX/...的注释,并注释掉url: "http://localhost:8080/...的逻辑。

Edit1:

error_page 405 = 200 $uri;上添加骇客nginx.conf可以消除此错误,但随后却给了我undefined

1 个答案:

答案 0 :(得分:0)

您的CORS中间件不完整-您还需要为preflight requests实现OPTIONS HTTP方法。基本上,405错误是不言自明的-您实施POST而不是OPTIONS

查看如何在Express的现有CORS中间件中is implemented-https://github.com/expressjs/cors