JavaScript循环内API请求按钮Bearer Token验证失败问题排查
问题分析与解决方案
核心问题原因
- 内联事件未传递Token:循环生成的按钮使用
onclick="fetchSingle();"调用函数,但未传入token参数,导致fetchSingle中token为undefined,请求时Authorization头无效,触发Token拒绝。 - 事件绑定时机错误: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
相关产品推荐
相关产品推荐

