【问题标题】:Axios post request works on Postman but not on browser (it returns "Error 401- Not Authorized")Axios 发布请求适用于 Postman,但不适用于浏览器(它返回“错误 401-未授权”)
【发布时间】:2021-10-15 08:34:03
【问题描述】:

我在使用 axios 发布请求时遇到问题。在浏览器中,如果我在控制台中选中“网络”,则会显示错误“401 - 未授权”。但是用 Postman 进行测试一切正常。 我已经尝试了几个在类似问题中公开的解决方案,但都没有成功。

这是我设置快递服务器的代码:

import express from "express";
import mongoose from "mongoose";
import cors from "cors";
import dotenv from "dotenv";
import authRouter from "./routes/auth.js";
import categoryRouter from "./routes/category.js";

//DOTENV CONFIG
dotenv.config();
const MONGODB_CONNECTION = process.env.MONGO_URI;

//INITIALIZE APP
const app = express();

//MIDDLEWARES
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.json());

app.use(cors());

//ROUTES
app.use("/api/auth", authRouter);
app.use("/api/categories", categoryRouter);

//PORT
const PORT = process.env.PORT || 5020;

//CONNECT MONGODB
const connectDB = () => {
  mongoose
    .connect(MONGODB_CONNECTION, {
      useNewUrlParser: true,
      useFindAndModify: true,
      useUnifiedTopology: true,
      useCreateIndex: true,
    })
    .then(() => console.log("MONGODB is connected"))
    .catch((err) => console.log("MONGODB connection error:", err));
};

connectDB();

//INITIALIZE SERVER
app.listen(PORT, () =>
  console.log(`Connection is established and running on port ${PORT}`)
);

这是与路由器设置相关的代码:

import express from "express";
import { getCategories, createCategory } from "../controllers/category.js";
import { authMiddleware, authAdminMiddleware } from "../middlewares/auth.js";

const router = express.Router();

router.route("/get-categories").get(getCategories);
router
  .route("/create-category")
  .post(authMiddleware, authAdminMiddleware, createCategory);

export default router;

用于身份验证的中间件:

import jwt from "jsonwebtoken";
import dotenv from "dotenv";
import { User } from "../models/User.js";

dotenv.config();
const JWT_SECRET = process.env.JWT_SECRET;

export const authMiddleware = async (req, res, next) => {
  try {
    let token;
    if (
      req.headers.authorization &&
      req.headers.authorization.startsWith("Bearer")
    ) {
      token = req.headers.authorization.split(" ")[1];
    }

    if (!token) {
      return res.status(401).json({ errorMessage: "Invalid Authentication" });
    }

    const decoded = jwt.verify(token, JWT_SECRET);
    const user = await User.findById(decoded.user._id);

    if (!user) {
      return res.status(404).json({ errorMessage: "No user found" });
    }

    req.user = user;

    next();
  } catch (error) {
    return res.status(500).json({ errorMessage: "Not authorized" });
  }
};

export const authAdminMiddleware = async (req, res, next) => {
  try {
    const user = await User.findOne({
      _id: req.user.id,
    });
    if (req.user.role === 0) {
      return res
        .status(400)
        .json({ errorMessage: "Not Authorized. Admin private route." });
    }
    next();
  } catch (error) {
    return res
      .status(401)
      .json({ errorMessage: "Not Authorized. Admin private route." });
  }
};

POST 请求控制器:

import { Category } from "../models/Category.js";
import slugify from "slugify";

export const createCategory = async (req, res) => {
  const { name, parentId } = req.body;

  try {
    if (!name) {
      return res
        .status(400)
        .json({ errorMessage: "Category name field is required." });
    }

    const category = await Category.findOne({ name });

    if (category) {
      return res.status(409).json({ errorMessage: "Category already exist." });
    }

    let id;

    if (parentId) {
      const findParentId = await Category.findOne({ name: parentId });
      if (findParentId) {
        id = findParentId._id;
      }
    }

    const newCategory = new Category({
      name,
      slug: slugify(name),
      parentId: id,
    });
    newCategory.save((err, saved) => {
      if (err) {
        return res.status(400).json({ errorMessage: err.message });
      }
      if (saved) {
        return res
          .status(201)
          .json({ successMessage: "Category created successfully!" });
      }
    });
  } catch (error) {
    res.status(500).json({ errorMessage: error.message });
  }
};

前端的 API 调用:

import axios from "axios";
import { getCookies } from "../helpers/storage&cookies/storage&cookies";

console.log(getCookies("token"));

const config = {
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer " + getCookies("token"),
  },
};

export const postCategory = async (data) => {
  const response = await axios.post(
    "http://localhost:5020/api/categories/create-category",
    data,
    config
  );
  return response;
};

具体的客户端发布请求:

import React, { useState } from "react";
import CreateCategoryModalUI from "./CreateCategoryModalUI";
import { postCategory } from "../../../api/category";

const CreateCategoryModal = ({ categories }) => {
  const [createCategoryData, setCreateCategoryData] = useState({
    name: "",
    parentId: "",
    errorMessage: "",
    successMessage: "",
    loading: false,
  });

  const { name, parentId, successMessage, errorMessage, loading } =
    createCategoryData;

  const handleChange = (e) => {
    if (e.target.type == "text") {
      setCreateCategoryData({
        ...createCategoryData,
        name: e.target.value,
        successMessage: "",
        errorMessage: "",
      });
    } else {
      setCreateCategoryData({
        ...createCategoryData,
        parentId: e.target.value,
        errorMessage: "",
        successMessage: "",
      });
    }
  };

  const handleSubmit = (e) => {
    e.preventDefault();

    if (!name) {
      setCreateCategoryData({
        ...createCategoryData,
        errorMessage: "Category name field is required.",
      });
    } else {
      const data = { name, parentId };
      console.log(data);
      setCreateCategoryData({
        ...createCategoryData,
        loading: true,
      });

      postCategory(data)
        .then((response) => {
          setCreateCategoryData({
            name: "",
            parentId: "",
            errorMessage: "",
            successMessage: response.data.successMessage,
            loading: false,
          });
        })
        .catch((error) => {
          if (error.response.status === 409) {
            setCreateCategoryData({
              ...createCategoryData,
              errorMessage: "Category already exists",
              loading: false,
            });
          } else {
            setCreateCategoryData({
              ...createCategoryData,
              errorMessage: error.toString(),
              loading: false,
            });
          }
        });
    }
  };

  return (
    <CreateCategoryModalUI
      createCategoryData={createCategoryData}
      categories={categories}
      handleChange={handleChange}
      handleSubmit={handleSubmit}
    />
  );
};

export default CreateCategoryModal;

我该如何解决这个问题? 非常感谢!

【问题讨论】:

  • 使用您的浏览器开发工具 Network 面板检查请求。 Authorization 标头中是否有正确的不记名令牌?此外,如果您使用 cors 包,则无需手动设置 CORS 响应标头
  • 是的,我已经检查过了:授权标头是正确的。此外,我还手动设置了 CORS 响应标头,因为对于另一个 POST 请求,我遇到了类似的问题,通过添加这两行代码莫名其妙地解决了。

标签: node.js express axios postman mern


【解决方案1】:

这是一个评论,但我没有足够的声誉来这样做,这就是我发布答案的原因。

您可以尝试在创建 Axios 实例时将 withCredentials 设置为 true,withCredentials 根据 Axios 存储库执行以下操作:

withCredentials表示是否跨站访问控制请求 应该使用凭据制作

官方文档没有添加任何进一步的解释...

axios.create({ withCredentials: true, })

【讨论】:

  • OP 正在使用不需要withCredentials的不记名令牌
  • 谢谢,我也尝试使用 {withCredentials: true},但尽管将“Access-Control-Allow-Origin”设置为我的客户端本地主机地址,但我收到此错误:“访问 XMLHttpRequest at . .. from origin ...已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:响应中的“Access-Control-Allow-Origin”标头的值不能是通配符“* ' 当请求的凭证模式为 'include' 时。由 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。"
【解决方案2】:

谢谢大家,我解决了!这个问题,正如我经常发生的那样,是一个疏忽。具体来说,在身份验证中间件中。 在这些代码行中:

const user = await User.findById (decoded.user._id)

我在“解码”后添加了一个多余的“用户”,但对象键只是“_id”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-16
    • 1970-01-01
    • 2018-03-25
    • 2020-07-19
    • 2022-09-25
    • 2018-06-22
    • 1970-01-01
    相关资源
    最近更新 更多