You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

前端携带Token请求后端接口出现TypeError,请求协助排查

JWT身份认证客户端请求失败排查

我实现了基于JWT的身份认证功能:前端登录后从后端获取Token并存入localStorage,点击提交按钮时携带Token请求受保护的/api/v1/inventories接口。用Postman测试所有接口都正常,但客户端发送请求时后端报错,无法定位问题,求协助。

Frontend Code

<script>
      const formDOM = document.querySelector(".form");
      const btnSubmitDOM = document.querySelector(".btn-submit");

      // get token form server
      formDOM.addEventListener("submit", async (e) => {
        e.preventDefault();
        const email = document.querySelector("#email").value;
        const password = document.querySelector("#password").value;

        try {
          const { data } = await axios.post(
            "http://localhost:3000/api/v1/auth/login",
            { email, password }
          );
          console.log("token", data.token);
          localStorage.setItem("token", data.token);
        } catch (error) {
          console.log(error);
        }
      });

      // after submit, if authenticated, goes to protective route
      btnSubmitDOM.addEventListener("click", async () => {
        const token = localStorage.getItem("token");

        console.log("toekn when press", token);

        try {
          const { data } = await axios.get("http://localhost:3000/api/v1/inventories", {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          });
          location.assign("/inventories");
        } catch (error) {
          localStorage.removeItem("token");
          console.log(error);
        }
      });
    </script>

Backend Code

const jwt = require("jsonwebtoken");

const auth = async (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith("Bearer")) {
    res.send("Auth route - Unauthenticated Error");
  }
  const token = authHeader.split(" ")[1];
  console.log("token is ", token);

  try {
    const payload = jwt.verify(token, 'secret');
    // console.log(payload);

    // attached to the inventories route
    req.user = {
      userId: payload.userId,
      email: payload.email,
    };
    // console.log(req.user)
    next();
  } catch (error) {
    console.log(error);
  }
};

module.exports = auth;

服务器端错误日志

token is  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MzY4ZjFiM2U1ODJlYmQ1MjJkODI4MGEiLCJlbWFpbCI6Imt5YXdAZ21haWwuY29tIiwiaWF0IjoxNjY3ODI3NzIzLCJleHAiOjE2NzA0MTk3MjN9.rptgRrYB4TrLQCxbB18JqMHd05LSox-LQuiLJS0L2Gw

/Users/kyawmyo/Desktop/software-development/nodejs-&-vanilajs-projects/inventories/middleware/authentication.js:8
  const token = authHeader.split(" ")[1];
                           ^

TypeError: Cannot read properties of undefined (reading 'split')

问题根源与修复方案

  1. 后端中间件逻辑漏洞
    认证中间件中,当authHeader不存在或格式不符合要求时,调用res.send()后没有终止后续代码执行,导致后续尝试对undefined的authHeader执行split()方法,触发类型错误。

    修复后的后端认证中间件代码:

    const jwt = require("jsonwebtoken");
    
    const auth = async (req, res, next) => {
      const authHeader = req.headers.authorization;
      if (!authHeader || !authHeader.startsWith("Bearer")) {
        // 发送错误响应后立即返回,终止后续代码执行
        return res.status(401).send("Auth route - Unauthenticated Error");
      }
      const token = authHeader.split(" ")[1];
      console.log("token is ", token);
    
      try {
        const payload = jwt.verify(token, 'secret');
        req.user = {
          userId: payload.userId,
          email: payload.email,
        };
        next();
      } catch (error) {
        console.log(error);
        // 捕获JWT验证失败的情况,返回401状态码
        return res.status(401).send("Invalid or expired token");
      }
    };
    
    module.exports = auth;
    
  2. 前端逻辑冲突优化
    原代码同时绑定了表单submit事件和按钮click事件,可能导致登录请求未完成、Token未存入localStorage时就触发受保护接口请求,此时token为null,构造出无效的请求头。建议将登录与请求受保护接口的逻辑整合:

    <script>
      const formDOM = document.querySelector(".form");
    
      // 登录并请求受保护接口
      formDOM.addEventListener("submit", async (e) => {
        e.preventDefault();
        const email = document.querySelector("#email").value;
        const password = document.querySelector("#password").value;
    
        try {
          // 登录获取Token
          const { data } = await axios.post(
            "http://localhost:3000/api/v1/auth/login",
            { email, password }
          );
          console.log("token", data.token);
          localStorage.setItem("token", data.token);
    
          // 登录成功后直接请求受保护接口
          const { data: inventoryData } = await axios.get("http://localhost:3000/api/v1/inventories", {
            headers: {
              Authorization: `Bearer ${data.token}`,
            },
          });
          location.assign("/inventories");
        } catch (error) {
          localStorage.removeItem("token");
          console.log(error);
        }
      });
    </script>
    

内容的提问来源于stack exchange,提问作者Kyaw Myo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 19:10:50