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

JavaScript循环内API请求按钮Bearer Token验证失败问题排查

问题分析与解决方案

核心问题原因

  1. 内联事件未传递Token:循环生成的按钮使用onclick="fetchSingle();"调用函数,但未传入token参数,导致fetchSingle中token为undefined,请求时Authorization头无效,触发Token拒绝。
  2. 事件绑定时机错误:jQuery的$('.clickMe').click(...)绑定事件时,fetchlist里的列表请求是异步操作,此时循环生成的按钮还未创建,事件仅绑定到初始存在的手动按钮,动态生成的按钮未触发该事件,反而执行了无参数的内联onclick。

修复步骤

步骤1:移除内联onclick属性

循环生成按钮时删除内联事件,避免全局作用域参数丢失问题。

步骤2:使用事件委托绑定动态元素

通过jQuery的事件委托(on方法),将事件绑定到父容器,确保后续动态生成的按钮也能触发事件并获取正确的token。

步骤3:优化fetchSingle函数

不再依赖全局event对象,改为直接接收token和myid参数,提升函数健壮性。

修改后的完整代码

JavaScript部分

// Create html container
const container = document.createElement('div');
container.setAttribute('class', 'container');
output.appendChild(container);

// Create html Card element
const card = document.createElement('div');
card.setAttribute('class', 'card-single');
container.appendChild(card);

// Create html object header
const h1 = document.createElement('h1');
h1.setAttribute('class', 'header');
h1.setAttribute('id', 'header');

// Create  date
const createdAt = document.createElement('p');
createdAt.setAttribute('class', 'date');

//==================================
// Step 1 : 获取JWT token
//==================================
fetch("https://myDomain/api/login", {
  method: "POST",
  body: JSON.stringify({ username: "username", password: "password" }),
  headers: { "Content-type": "application/json" }
})
.then((res) => res.json())
.then((res) => {
  console.log(res);
  return res.token;
})
.then((token) => {
  fetchlist(token);
  // 事件委托:绑定父容器,覆盖所有动态生成的.clickMe元素
  $('#content').on('click', '.clickMe', function() {
    fetchSingle(token, this.value);
  });
});

//==================================
// Step 2 : 获取Pokemon列表
//==================================
const fetchlist = (token) => {
  const baseUrl = "https://myDomain/api/pokemons/"
  try {
    fetch(baseUrl, {
      headers: {Authorization: `Bearer ${token}`}
    })
    .then((response) => {
      if (response.status == 200) {
        return response.json();
      } else {
        throw new Error("NETWORK RESPONSE ERROR");
      }
    })
    .then((poke) => {
      displayList(poke);
    })
    .catch(error => {
      console.error(error)
    });
  } catch (error) {
    console.error(error)
  }

  const contentDiv = document.getElementById("content");
  const container = document.createElement('div');
  container.setAttribute('class', 'container');
  contentDiv.appendChild(container);

  container.insertAdjacentHTML('beforebegin',
    // 手动按钮(可选保留)
    `
      <input type="text" class="clickMe" placeholder="输入ID">
    `
  )

  function displayList(poke) {
    for (let i in poke.data) {
      let z = poke.data[i];

      // Create html for Card element
      const card = document.createElement('div');
      card.setAttribute('class', 'card');
      container.appendChild(card);

      // 移除内联onclick,仅保留必要属性
      card.insertAdjacentHTML('beforeend',
          `
           <input type="text" value="${z.id}" class="clickMe" readonly>
          `
      )
      // Create html for object name
      const h1 = document.createElement('h1');
      h1.setAttribute('class', 'header');
      h1.innerHTML = z.name;
      card.appendChild(h1);
    }
  }
}

//==================================
// Step 3 : 获取单个Pokemon详情
//==================================
const fetchSingle = (token, myid) => {
  console.log("Myid : " + myid );

  if (!myid) {
    console.log("ID为空");
    return;
  }

  try {
    fetch(`https://myDomain/api/pokemons/${myid}`, {
      headers: {Authorization: `Bearer ${token}`}
    })
    .then((singleresponse) => {
      if (singleresponse.status == 200) {
        return singleresponse.json();
      } else {
        throw new Error("NETWORK RESPONSE ERROR");
      }
    })
    .then((single) => {
      displaySingle(single);
    })
    .catch(error => {
      console.error(error)
    });
  } catch (error) {
    console.error(error)
  }

  function displaySingle(single) {
    const poke = single.data;

    // 更新名称
    h1.textContent = poke.name;
    card.appendChild(h1);

    // 更新创建时间
    const createDate = new Date(poke.created);
    createdAt.textContent = "Created at : " + createDate.toLocaleString(undefined, {timeZone: 'UTC'});
    card.appendChild(createdAt);
  }
}

关键修改说明

  • 事件委托:通过$('#content').on('click', '.clickMe', ...)确保动态生成的按钮能触发点击事件,直接传递token和按钮的value(Pokemon ID)。
  • 函数参数优化:fetchSingle直接接收token和myid,不再依赖全局event对象,避免参数丢失。
  • 移除内联事件:删除循环内按钮的onclick属性,消除无效调用。

修改后,循环生成的按钮点击时会正确携带Token请求详情接口,解决认证被拒绝问题。

内容的提问来源于stack exchange,提问作者Paquito Uman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 08:06:18