jQuery AJAX调用导致错误状态403
我正在使用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%确信这不是服务器端身份validation或权限错误。 再一次,服务器端的一切都是敞开的。 这意味着我在客户端请求上犯了一些错误。
我觉得我应该知道这个请求是在开发期间做出的。 所以,我是从http:// localhost:3000运行的 。 出于这个原因,我立即认为这是一个CORS问题。 但一切看起来都很正确 事实上我的POST请求有效,但我的GET并没有让我绝对感到沮丧。 我错过了什么吗? 会是什么呢?
403错误的原因是您没有发送标头 。 由于您正在发出CORS请求,因此除非服务器通过向响应添加Access-Control-Allow-Headers
来启用这些标头,否则您无法发送任何自定义标头。
在预检请求中 ,客户端向服务器发出2个请求。 第一个是预检(使用OPTION方法),第二个是实际请求。 服务器发送Access-Control-Allow-Headers标头作为预检请求的响应。 因此它可以发送一些标头。 通过这种方式,您的POST请求可以正常工作,因为POST请求是预检请求。 但是对于GET请求,没有预检来收集Access-Control-Allow-Headers标头。 因此浏览器不会发送您的自定义标头。
此问题的解决方法:
要解决此问题,请将dataType
和contentType
设置为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);
添加:
实际上,在执行jsonp请求时, contentType
应该是application/javascript
或application/json
。 没有contentType
作为jsonp
。
如果您查看jQuery的Ajax调用的API页面 ,它会在Content-Type部分中提到以下内容:
注意:对于跨域请求,将内容类型设置为application / x-www-form-urlencoded,multipart / form-data或text / plain以外的任何内容将触发浏览器向服务器发送预检OPTIONS请求。
那个页面并没有真正提到“预检OPTIONS请求”是什么,但我在网上查找这个短语时发现了一些有趣的链接:
- 预检Blob请求
- 使用CORS的 HTML 5 Rocks
- W3C的跨源资源共享规范
- 使用CORS进行跨域Ajax请求
有什么问题是HTML5Rocks页面上的代码示例和CORS图像 。 该图显示了如何从JavaScript代码到浏览器到服务器进行Ajax调用以及响应如何在所有这三个之间进行往返。
我们倾向于考虑JavaScript + Browser = Client,但在插图中,作者正在解释Web开发人员代码与浏览器开发人员代码之间的区别,前者是用JavaScript代码编写的,后者是用C,C ++编写的。或C#代码。
一个好的数据包分析工具是Fiddler ,它与Wireshark类似。 这些工具中的任何一个都应该向您显示从浏览器发送到服务器的飞行前请求。 最可能的情况是,服务器阻止了您的Ajax请求,并出现403 Forbidden错误 。