我正在使用 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 请求却没有让我完全沮丧。我错过了什么吗?可能是什么?
403错误的原因是你没有发送标头。由于您正在发出 CORS 请求,因此您无法发送任何自定义标头,除非服务器通过在响应中添加
Access-Control-Allow-Headers
来启用这些标头。
在预检请求中,客户端向服务器发出 2 个请求。第一个是预检(使用 OPTIONS 方法),第二个是真正的请求。服务器发送 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
});
这样,你的 get 请求将是一个
preflighted request
。如果您的服务器启用 api-key
和 Access-Control-Allow-Headers 标头,它将起作用。
上述请求的示例服务器配置(用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 将触发浏览器发送预检选项 向服务器请求。
该页面并没有真正提到什么是“预检选项请求”,但我在网上查找该短语时发现了一些有趣的链接:
有趣的是 HTML5Rocks 页面上的 代码示例 和 CORS 图像。该图显示了如何从 JavaScript 代码到浏览器再到服务器进行 Ajax 调用,以及响应如何在所有 3 个代码之间往返。
我们倾向于认为 JavaScript + 浏览器 = 客户端,但在插图中作者解释了 Web 开发人员的代码和浏览器开发人员的代码之间的区别,前者是用 JavaScript 代码编写的,而后者是使用 C 编写的, C++ 或 C# 代码。
一个好的数据包分析工具是Fiddler,它类似于Wireshark。这些工具中的任何一个都应该向您显示从浏览器发送到服务器的飞行前请求。最有可能的是,您的 Ajax 请求被服务器阻止,并出现 403 Forbidden 错误。
另请参阅这篇文章,其中讨论了 Google 翻译扩展将无关 HTML 附加到某些页面元素的问题。
例如,在上面链接的情况下,谷歌翻译附加了这些行
<p> </p>
<div id="gtx-trans" style="position: absolute; left: -28px; top: -8px;"> </div>
转到 TinyMCE 编辑器内容。当用户输入的数据发送到后端时,其中包含谷歌翻译添加内容,这导致了 403 错误。
面临一些问题,上传 pdf 时显示 ajax 调用错误 403 禁止填充以禁用 MSIE 和 Chrome 友好错误页面,这是我的 ajax 调用 >> 上传 pdf ajax 调用,请解决此问题
$.ajax({
headers: {
"X-CSRF-TOKEN": csrf
},
enctype: 'multipart/form-data',
processData: false, // Important!
contentType: false,
dataType: 'json',
// contentType: 'json',
cache: false, //this is my servlet
crossDomain: true, // Set this option
data: data,
type: "POST",
url: "./parseResume",
success: function(result) {
if (result.status == "Done") {
current_employee_id = result.data.employeeId;
$('#myModal').modal('hide');
// $('#candidatesBlock1').empty();
}
$(".tab-slider--navresumedetails li:nth-child(2)").trigger('click')
$(".tab-slider--navresumedetails li:nth-child(1)").css('pointer-events', 'none');
// $(".add_candidate_form_parent").css('height', '698px');
$(".add_candidate_form_parent").css('overflow', 'auto');
getSupplierEmail()
var obj = result.data;
unparsed_resumes_list = obj;
current_employee_id = obj.employeeId;
$('#userId_unparesedResume').val(obj.employeeId);
unparsedBulkSharedResumePreview(obj); $('#btn_save_unparsedSharedBulkResumes').html('Save');
if (result.status == "error") {
$('#myModal').modal('hide');
}
},
error: function(result) {
console.log(result);
}
});