Answers:
POST
由于相同来源策略的(相当明智的)限制,因此无法与另一个域上的服务进行异步。JSON-P之所以起作用,是因为允许您将<script>
标签插入DOM,并且它们可以指向任何地方。
当然,您可以使用常规形式的POST来使另一个域上的页面。
编辑:如果您愿意花很多精力插入隐藏的s并对其属性进行处理,那么会有一些有趣的技巧<iframe>
。
POST
只要该域和您的浏览器都支持,您当然可以向其他域发出请求CORS
。但它是完全真实的POST
和JSONP
不兼容。
<script>
指向另一个域的标签来实现的。在浏览器中执行POST请求的唯一方法是通过HTML表单或XMLHttpRequest。
如果需要跨域发送大量数据。我通常会创建一个可以分两步调用的服务:
首先,客户进行FORM提交(允许跨域发布)。该服务将输入存储在服务器上的会话中(使用GUID作为键)。(客户端创建GUID并将其作为输入的一部分发送)
然后,客户端将使用与FORM帖子中使用的GUID相同的GUID作为参数进行普通脚本注入(JSONP)。该服务处理来自会话的输入,并以正常的JSONP时尚形式返回数据。在此之后,会话被破坏。
当然,这取决于您编写服务器后端。
XMLHttpRequest
根本不应该参与其中。Per的答案使用常规表单提交来发出POST请求,然后使用脚本元素注入来发出GET请求。
我知道这是严重的死法,但是我想我应该使用jQuery发布JSONP POST的实现,我已经成功地将其用于JS小部件(用于客户注册和登录):
基本上,我使用的是IFrame方法,如公认的答案所建议。我做的不同的是,发送请求后,我正在监视,如果可以使用计时器在iframe中访问表单。如果无法到达表格,则表示请求已返回。然后,我使用普通的JSONP请求来查询操作状态。
我希望有人觉得它有用。在> = IE8,Chrome,FireFox和Safari中进行了测试。
function JSONPPostForm(form, postUrl, queryStatusUrl, queryStatusSuccessFunc, queryStatusData)
{
var tmpDiv = $('<div style="display: none;"></div>');
form.parent().append(tmpDiv);
var clonedForm = cloneForm(form);
var iframe = createIFrameWithContent(tmpDiv, clonedForm);
if (postUrl)
clonedForm.attr('action', postUrl);
var postToken = 'JSONPPOST_' + (new Date).getTime();
clonedForm.attr('id', postToken);
clonedForm.append('<input name="JSONPPOSTToken" value="'+postToken+'">');
clonedForm.attr('id', postToken );
clonedForm.submit();
var timerId;
var watchIFrameRedirectHelper = function()
{
if (watchIFrameRedirect(iframe, postToken ))
{
clearInterval(timerId);
tmpDiv.remove();
$.ajax({
url: queryStatusUrl,
data: queryStatusData,
dataType: "jsonp",
type: "GET",
success: queryStatusSuccessFunc
});
}
}
if (queryStatusUrl && queryStatusSuccessFunc)
timerId = setInterval(watchIFrameRedirectHelper, 200);
}
function createIFrameWithContent(parent, content)
{
var iframe = $('<iframe></iframe>');
parent.append(iframe);
if (!iframe.contents().find('body').length)
{
//For certain IE versions that do not create document content...
var doc = iframe.contents().get()[0];
doc.open();
doc.close();
}
iframe.contents().find('body').append(content);
return iframe;
}
function watchIFrameRedirect(iframe, formId)
{
try
{
if (iframe.contents().find('form[id="' + formId + '"]').length)
return false;
else
return true;
}
catch (err)
{
return true;
}
return false;
}
//This one clones only form, without other HTML markup
function cloneForm(form)
{
var clonedForm = $('<form></form>');
//Copy form attributes
$.each(form.get()[0].attributes, function(i, attr)
{
clonedForm.attr(attr.name, attr.value);
});
form.find('input, select, textarea').each(function()
{
clonedForm.append($(this).clone());
});
return clonedForm;
}
通常,JSONP是通过<script>
在调用文档中添加标签来实现的,因此JSONP服务的URL为“ src”。浏览器通过HTTP GET事务获取脚本源。
现在,如果您的JSONP服务与调用页面位于同一域中,那么您可能可以通过简单的$.ajax()
调用将某些内容拼凑起来。如果不在同一个域中,那么我不确定怎么可能。
CORS
那么只要浏览器也支持它就可以。在这些情况下,您将使用Plain JSON
而不是JSONP
。
我已经做了很多次(黑客)解决方案,您可以使用JsonP进行发布。(您将能够张贴表格,大于2,000个字符,超过GET可以使用的字符)
客户端应用程序Javascript
$.ajax({
type: "POST", // you request will be a post request
data: postData, // javascript object with all my params
url: COMAPIURL, // my backoffice comunication api url
dataType: "jsonp", // datatype can be json or jsonp
success: function(result){
console.dir(result);
}
});
JAVA:
response.addHeader( "Access-Control-Allow-Origin", "*" ); // open your api to any client
response.addHeader( "Access-Control-Allow-Methods", "POST" ); // a allow post
response.addHeader( "Access-Control-Max-Age", "1000" ); // time from request to response before timeout
PHP:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Max-Age: 1000');
这样做,您正在向任何发布请求打开服务器,您应该通过提供ident或其他方式来确保安全。
使用此方法,您还可以将请求类型从jsonp更改为json,两者都起作用,只需设置正确的响应内容类型
jsonp
response.setContentType( "text/javascript; charset=utf-8" );
json
response.setContentType( "application/json; charset=utf-8" );
请注意,您的服务器将不再尊重SOP(相同来源策略),但是谁在乎呢?
<script>
标记注入HTML DOM 外,您还可以同时使用JSON和JSONP数据表示法(哎呀,您甚至可以在桌面应用程序中使用它们,说您想向同一服务器发出多个JSON请求,并且想要使用函数名作为请求跟踪ID)。
有可能,这是我的解决方案:
在您的JavaScript中:
jQuery.post("url.php",data).complete(function(data) {
eval(data.responseText.trim());
});
function handleRequest(data){
....
}
在您的url.php中:
echo "handleRequest(".$responseData.")";