405 (не разрешено) ~ Vue.js ~ Nginx ~ Axios ~ SQLite ~ Express ~ - PullRequest
0 голосов
/ 07 октября 2019

У меня есть простое приложение, которое регистрирует и регистрирует пользователей в базе данных SQLite, которое прекрасно работает на localhost, но не может заставить его работать при развертывании. Возвращает ошибку 405 (Not Allowed) с Error: Request failed with status code 405. Мой сервер - Ubuntu, на котором работает Nginx.

Мои действия (с использованием Vuex) для обработки имени входа / регистрации behviours:

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 голосов
/ 07 октября 2019

Ваше промежуточное ПО CORS не завершено - вам также нужно реализовать OPTIONS HTTP-метод для предварительных запросов . По сути, ошибка 405 не требует пояснений - вы реализуете POST, но не OPTIONS.

Посмотрите, как реализовано в существующем промежуточном программном обеспечении CORS для Express - https://github.com/expressjs/cors

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...