0

注意:我没有足够的声誉来发布所有链接,所以我只是删除了第一个字母,以便文本编辑器不会将其视为链接。要找到他们,只需将其粘贴到您的地址栏中并在前面添加一个 h。

我正在尝试使用可汗学院的 API 访问用户数据,但是,这是我第一次使用他们的 API 或 AJAX。到目前为止,我已经成功地检索了有关视频或练习的数据,但是在使用 OAuth 检索用户数据时遇到了麻烦。这是可汗学院授权的信息。他们使用 OAuth 1.0。这是我正在使用的 OAuth 库。这是 KA API 的文档:http: //api-explorer.khanacademy.org/我试过了:

var oauth = OAuth({
  consumer: {
    public: '****************',
    secret: '****************'
  },
  signature_method: 'HMAC-SHA1'
});

var request_data = {
  url: 'http://www.khanacademy.org/api/v1/exercises/logarithms_1',
  method: 'GET'
};

$.ajax({
  url: request_data.url,
  type: request_data.method,
  headers: oauth.toHeader(oauth.authorize(request_data))
}).done(function(data) {
  alert("done");
});
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
  <title>KA API Test</title>
  <meta http-equiv="Access-Control-Allow-Origin" content="*">
  <meta http-equiv="content-type" content="text/html;charset=utf-8" />
  <meta name="generator" content="Geany 1.23.1" />
  <!-- sha1 -->
  <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha1.js"></script>
  <!-- sha256 -->
  <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha256.js"></script>

  <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js"></script>
  <script src="oauth-1.0a.js"></script>
  <script src="jquery-1.12.0.min.js"></script>
</head>

<body>
</body>

</html>

我也用相同的 HTML 尝试过这个 Javascript:

var oauth = OAuth({
  consumer: {
    public: 'qdMdMjjJQKrwJw2S',
    secret: '7XeknfpVBzx8fGMK'
  },
  signature_method: 'HMAC-SHA1'
});

var request_data = {
  url: 'http://www.khanacademy.org/api/v1/exercises/logarithms_1',
  method: 'GET'
};

var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.khanacademy.org/api/v1/exercises/logarithms_1", true);
xhr.setRequestHeader("Authorization", oauth.toHeader(oauth.authorize(request_data)));
xhr.send();
xhr.addEventListener("readystatechange", processRequest, false);

function processRequest(e) {
  if (xhr.readyState == 4 && xhr.status == 200) {
    var response = JSON.parse(xhr.responseText);
    for (var key in response) {
      console.log(key + ":" + response[key]);
    }
    alert(response.translated_description_html);
  }
}

两者都在控制台中给出了这个错误:“XMLHttpRequest cannot load http://www.khanacademy.org/api/v1/exercises/logarithms_1。对预检请求的响应没有通过访问控制检查:没有'Access-Control-Allow-请求的资源上存在 Origin 标头。因此不允许访问Origin ' http://localhost '。

注意: XMLHttpRequest 工作正常,并在添加之前返回我想要xhr.setRequestHeader("Authorization", "OAuth " + oauth.toHeader(oauth.authorize(request_data)));的内容。但是,这只是一个不需要授权的测试链接,我稍后会更改它。

PS我想修复这个错误,但我也只需要正确使用OAuth,我认为它们是相关的,因为在使用OAuth之前我没有错误。

4

1 回答 1

0

问题在于跨域访问源。您需要请求 API 所有者允许跨域来源。

Access-Control-Allow-Origin is a CORS (Cross-Origin Resource Sharing) header.

当站点 A 尝试从站点 B 获取内容时,站点 B 可以发送一个 Access-Control-Allow-Origin 响应标头,告诉浏览器该页面的内容可以从某些来源访问。(源是一个域,加上一个方案和端口号。)默认情况下,任何其他源都无法访问站点 B 的页面。使用 Access-Control-Allow-Origin 标头为特定请求来源的跨域访问打开了一扇门。

对于站点 B 希望站点 A 可以访问的每个资源/页面,站点 B 应为其页面提供响应标头:

Access-Control-Allow-Origin:http://siteA.com 现代浏览器不会直接阻止跨域请求。如果站点 A 从站点 B 请求页面,浏览器实际上将在网络级别获取请求的页面并检查响应标头是否将站点 A 列为允许的请求者域。如果站点 B 没有表明站点 A 被允许访问该页面,浏览器将触发 XMLHttpRequest 的错误事件并拒绝响应数据给请求的 JavaScript 代码。

非简单请求 网络级别发生的事情可能比上面解释的稍微复杂一些。如果请求是“非简单”请求,浏览器首先发送一个无数据的“预检”OPTIONS 请求,以验证服务器是否会接受该请求。当任一(或两者)时,请求是非简单的:

使用 GET 或 POST 以外的 HTTP 动词(例如 PUT、DELETE),使用非简单请求标头;唯一简单的请求标头是: Accept Accept-Language Content-Language Content-Type(仅当其值为 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 时才简单)如果服务器使用与非简单动词和/或非简单标题匹配的适当响应标题(非简单标题的 Access-Control-Allow-Headers,非简单动词的 Access-Control-Allow-Methods)响应 OPTIONS 预检,然后浏览器发送实际请求。

假设站点 A 想要发送一个对 /somePage 的 PUT 请求,其 Content-Type 值为 application/json,浏览器将首先发送一个预检请求:

OPTIONS /somePage HTTP/1.1 来源:http ://siteA.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: Content-Type 注意 Access-Control-Request-Method 和 Access-Control-Request - 标题由浏览器自动添加;您不需要添加它们。此 OPTIONS 预检获取成功的响应标头:

Access-Control-Allow-Origin: http://  siteA.com

Access-Control-Allow-Methods: GET, POST, PUT

Access-Control-Allow-Headers: Content-Type

发送实际请求时(预检完成后),其行为与处理简单请求的方式相同。换句话说,预检成功的非简单请求被视为与简单请求相同(即,服务器仍必须再次发送 Access-Control-Allow-Origin 以获得实际响应)。

浏览器发送实际请求:

PUT /somePage HTTP/1.1 来源:http://siteA.com 内容类型:application/json

{ "myRequestContent": "Response in JSON" } 然后服务器发回一个 Access-Control-Allow-Origin,就像它对一个简单的请求一样:

Access-Control-Allow-Origin:http://siteA.com 有关非简单请求的更多信息,请参阅Understanding XMLHttpRequest over CORS。

于 2016-04-03T05:12:19.227 回答