【问题标题】:jQuery AJAX call results in error status 403jQuery AJAX 调用导致错误状态 403
【发布时间】:2016-08-08 13:18:33
【问题描述】:

我正在使用 jQuery AJAX 对 Web 服务进行查询。我的查询如下所示:

var serviceEndpoint = 'http://example.com/object/details?version=1.1';
$.ajax({
  type: 'GET', 
  url: serviceEndpoint,
  dataType: 'jsonp',
  contentType: 'jsonp',
  headers: { 'api-key':'myKey' },
  success: onSuccess,
  error: onFailure
});

执行此操作时,我收到状态错误 403。我不明白为什么我的调用会导致状态代码为 403。我控制着我的服务的安全性,它被标记为完全开放.我知道密钥是有效的,因为我在另一个调用中使用它,它有效。这是有效的调用:

var endpoint = 'http://example.com/object/data/item?version=1.1';
$.ajax({ 
  type: 'POST', 
  url: endpoint, 
  cache: 'false',
  contentType:'application/json',
  headers: {
    'api-key':'myKey',
    'Content-Type':'application/json'
  },
  data: JSON.stringify({
    id: 5,
    count:true
  }),
  success: onDataSuccess,
  error: onDataFailure
});

我知道这是两个不同的端点。但我 100% 确信这不是服务器端身份验证或权限错误。再一次,服务器端的一切都是开放的。这意味着我在客户端请求上犯了一些错误。

我觉得我应该传达这个请求是在开发过程中提出的。所以,我从http://localhost:3000 运行这个。出于这个原因,我立即认为这是一个 CORS 问题。但一切看起来都是正确的。我的 POST 请求有效,但我的 GET 并没有让我感到非常沮丧。我错过了什么吗?会是什么?

【问题讨论】:

  • 您是否尝试过直接在浏览器中打开该网址?您是否错过了网址的 /data/ 部分以匹配有效的部分?
  • 请注意,jsonp 请求不能发送标头,它是脚本请求。您确定要jsonp 而不是json?还有为什么 JSON.stringify() 用于标题? GET 没有请求contentType。因为没有发送正文内容。你有很多问题,其中任何一个都可能是问题
  • @charlietfl 我确实尝试在浏览器中打开。我不熟悉我需要包含的任何/data/ 部分。我几乎只需要传递versionapi-key。我认为我应该将api-key 作为标题。我是否需要将datacontentType 属性设置为jsonp?这似乎应该是一个简单的调用。但很明显,我搞砸了,忽略了一些东西。正确的调用应该是什么样的?
  • jsonp 是一种不同于 ajax 的请求类型,并且不允许标头。从所显示的内容中对问题的了解还不够
  • 你在用chrome吗?你的后端技术是什么?

标签: jquery ajax cors http-status-code-403


【解决方案1】:

403 错误的原因是您没有发送标头。由于您正在发出 CORS 请求,因此您无法发送任何自定义标头,除非服务器通过在响应中添加 Access-Control-Allow-Headers 来启用这些标头。

preflighted-request 中,客户端向服务器发出 2 个请求。第一个是预检(使用 OPTIONS 方法),第二个是真正的请求。服务器发送Access-Control-Allow-Headers 标头作为预检请求的响应。因此,它可以发送一些标头。通过这种方式,您的 POST 请求可以工作,因为 POST 请求是一个预检请求。但是对于 GET 请求,没有预检来收集 Access-Control-Allow-Headers 标头,并且在这种情况下浏览器不会发送您的自定义标头。

解决此问题的方法:

作为一种解决方法,将dataTypecontentType 设置为json,如下所示:

var serviceEndpoint = 'http://example.com/object/details?version=1.1';
$.ajax({
  type: 'GET', 
  url: serviceEndpoint,
  dataType: 'json',
  contentType: 'json',
  headers: { 'api-key':'myKey' },
  success: onSuccess,
  error: onFailure
});

通过这种方式,您的获取请求将是preflighted request。如果您的服务器启用带有Access-Control-Allow-Headers 标头的api-key,它将起作用。

上述请求的示例服务器配置(用 express.js 编写):

res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', '*');
res.setHeader('Access-Control-Allow-Headers', 'api-key,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);

添加:

实际上,contentType 在进行 jsonp 请求时应该是 application/javascriptapplication/json。没有contentTypejsonp

【讨论】:

  • res.setHeader 代码应该写在哪里?还有,res是什么对象?
  • @Zoran777 它将在服务器端。 here is the docs 用于resexpress 服务器中。
【解决方案2】:

如果您查看 jQuery 的 Ajax 调用的 API page,它会在 Content-Type 部分提到以下内容:

注意:对于跨域请求,将内容类型设置为任意 除了 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 将触发浏览器发送预检选项 向服务器请求。

该页面并未真正提及“预检选项请求”是什么,但我在网上查找该短语时发现了一些有趣的链接:

有趣的是 HTML5Rocks 页面上的 code exampleCORS image。该图显示了从 JavaScript 代码到浏览器再到服务器的 Ajax 调用是如何进行的,以及响应如何在所有 3 个之间进行往返。

我们倾向于认为 JavaScript + Browser = Client,但在插图中作者正在解释 Web 开发人员的代码和浏览器开发人员的代码之间的区别,前者是用 JavaScript 代码编写的,而后者是用 JavaScript 代码编写的C、C++ 或 C# 代码。

一个好的数据包分析工具是Fiddler,它类似于Wireshark。这些工具中的任何一个都应该向您显示从浏览器发送到服务器的飞行前请求。很可能,这就是您的 Ajax 请求被带有 403 Forbidden error 的服务器阻止的地方。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 2023-03-15
    • 2013-01-29
    • 2011-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多