这个问题是在几天前发布的,但由于我是一个小块,它充满了意大利面条代码和那种东西(请原谅表格处理)除此之外,我添加了一些笔记和给出了一些上下文,但问题仍然在于第二次AJAX调用。
这是Chrome投掷的错误“仅支持协议方案的跨源请求:http,数据,Chrome,Chrome扩展,https,chrome-extension-resource。”
我隐藏了网址,因为它包含我不想分享的API密钥。
热烈欢迎任何批评
/*
This module will take a user's name, return an ID
then search more stats in the api with the ID.
*/
var search = document.getElementById('search');
search.addEventListener('click', function(){
var demo = document.getElementById('demo');
var player_name = document.getElementById('player_name').value;
var player_id;
// Interpolated API URLs
var name_url = 'URL.pre'+player_name+'URL.end';
var stats_url; //nested in the second ajax call to pass updated player_id
// Get player ID
var xhr = new XMLHttpRequest();
var id_return_text;
xhr.onload = function(){
if(xhr.status === 200) {
id_return_text = JSON.parse(xhr.responseText);
player_id = id_return_text[player_name].id;
demo.innerHTML = id_return_text[player_name].name +', your player ID is: '+player_id;
}
};
xhr.open('GET', name_url, true);
xhr.send();
// Search stats with ID
var xhr_2 = new XMLHttpRequest();
var stats_return_text;
xhr.done = function(){
stats_url = "URL.pre"+player_id+"URL.end";
if(xhr_2.status == 200) {
stats_return_text = JSON.parse(xhr_2.responseText);
demo.innerHTML += stats_return_text['playerStatsSummaries'].playerStatType;
}
};
xhr_2.open("GET",stats_url, true);
xhr_2.send();
});
<div id="container">
<img id="duck" src="duck.png" alt="duck">
<div class="form_wrapper">
<h1 id="app_header">*QUACK* What's Your player ID?</h1>
<form>
<input
type="text"
id="player_name"
placeholder="Summoner Name">
<input type="button" id="search" value="Search">
</form>
</div>
<p id="demo"></p>
</div>
<script type="text/javascript" src="script.js"></script>
答案 0 :(得分:1)
所以你的主要错误是,如果你需要发出CORS请求(或任何真正的AJAX请求),你需要从服务器(甚至是localhost)运行代码。
如果您的网页协议是&#34; file:///&#34;那么Google(以及大多数浏览器)都会对您不满。并且你试图从互联网上加载东西(反之亦然)。和&#34; file:///&#34;也无法请求其他文件。未来参考:你也不能制作&#34; http&#34;来自&#34; https&#34;的请求页。
这样,第二个问题(CORS安全性隐藏的问题)就是你的AJAX请求正在并行运行。
为了让你的工作按照你认为应该的方式进行(在第一个返回后运行第二个),你需要:
xhr_2
xhr.onload
相关
xhr.done
内部xhr.onload
内的所有代码并替换所有重复信息(并直接使用对返回结果的引用)这导致类似:
var search = document.getElementById('search');
search.addEventListener('click', function(){
var demo = document.getElementById('demo');
var player_name = document.getElementById('player_name').value;
var player_id;
// Interpolated API URLs
var name_url = 'https://na.api.pvp.net/api/lol/na/v1.4/summoner/by-name/'+player_name+'?api_key=<THIS IS THE API KEY>';
var stats_url; //nested in the second ajax call to pass updated player_id
// Get player ID
var xhr = new XMLHttpRequest();
var id_return_text;
xhr.onload = function(){
if(xhr.status === 200) {
id_return_text = JSON.parse(xhr.responseText);
player_id = id_return_text[player_name].id;
demo.innerHTML = id_return_text[player_name].name +', your player ID is: '+player_id;
// Dropped the XHR_2 stuff here
var xhr_2 = new XMLHttpRequest();
var stats_return_text;
stats_url = "https://na.api.pvp.net/api/lol/na/v1.3/stats/by-summoner/"+player_id+"/summary?season=SEASON2016&api_key=<THIS IS THE API KEY>";
// CHANGED THIS TO BE XHR_2.onload -- IN HERE I KNOW XHR_1 IS ALREADY FINISHED
xhr_2.onload = function(){
if(xhr_2.status == 200) {
stats_return_text = JSON.parse(xhr_2.responseText);
demo.innerHTML += stats_return_text['playerStatsSummaries'].playerStatType;
}
};
xhr_2.open("GET",stats_url, true);
xhr_2.send();
}
};
xhr.open('GET', name_url, true);
xhr.send();
});
这几乎可以解决你所有的困境。
关键是onload
是一个回调,它在程序运行后很长时间内被触发,但xhr_2
在您请求xhr_1
的数据后立即触发(不是之后)它正在返回数据。)
因此,player_id
未定义。
我们希望等到我们知道player_id
之后,当我们回到xhr_1.onload
的回调中时,我们知道我们已经有了(或者有些错误)。
这非常令人困惑并且非常嵌套,虽然我认为Promise和异步函数/生成器是管理这种复杂性的绝佳解决方案,但这超出了这个范围;所以相反,我建议查看一些功能组合,以简化所有这些:
function noop () { } // do nothing
function getJSON (url, onload, onerror) {
var xhr = new XMLHttpRequest();
onload = onload || noop; // what I've been given or nothing
onerror = onerror || noop; // " "
xhr.onload = function () {
var data;
var error;
try {
// it's possible for parse to throw on malformed JSON
data = JSON.parse(xhr.responseText);
} catch (e) {
error = e;
}
return error ? onerror(error) : onload(data); // fire one or the other (don't fall into the handler, if onload throws)
};
xhr.onerror = onerror;
xhr.open("GET", url);
xhr.send();
}
// localize URL construction
function buildPlayerIdUrl (name) { return "https://______" + name + "_____"; }
function buildPlayerStatsUrl (id) { return "https://______" + id + "_____"; }
// gets player by name and runs a function after the player has been loaded
function getPlayer (player_name, done, error) {
var id_url = buildPlayerIdUrl(player_name);
function buildPlayer (response) {
var player = response[player_name];
return player;
}
function onload (response) {
done(buildPlayer(response));
}
// Load the JSON, build the player, pass the player to done()
getJSON(url, onload, error);
}
// get stats by player id and runs a function after the stats have been loaded
function getPlayerStats (player_id, done, error) {
var stats_url = buildPlayerStatsUrl(player_id);
function buildStats (response) {
var summary = response.playerStatsSummaries;
return summary;
}
function onload (response) {
done(buildStats(response));
}
// Load the JSON, build the stats, pass the stats to done()
getJSON(stats_url, onload, error);
}
// perform a search by player name
// note: All changes in step-number (1, 2, 3) are asynchronous,
// and thus, must be nested in callbacks of some sort
function search (player_name) {
// Step 1: load the player
getPlayer(playerName, function (player) {
// Step 2a: update the DOM with the player name/id
updatePlayerDom(player);
// Step 2b: load the player stats
getPlayerStats(player.id, function (stats) {
// Step 3: update the DOM with the stats
updateStatsDom(stats);
});
});
}
// player DOM update; keeping it nice and simple
function updatePlayerDom (player) {
document.querySelector(".Player-id").textContent = player.id;
document.querySelector(".Player-name").textContent = player.name;
}
// stats DOM update; same as above
function updateStatsDom (stats) {
document.querySelector(".Player-stats").textContent = stats.playerStatType;
}
// bootstrap yourself to your UI
some_button.onclick = function () {
var player_name = some_input.value;
search(player_name); // kick the whole thing off
};
这绝对是更多的代码,但是对每个单独的部分进行编辑也更简单,而不会踩到其他部分的脚趾。
它(希望)也更容易看到所有部分的 _eventual timeline _ ,以及它们如何在search( )
本身内流动。