将数据发布到JsonP

时间:2010-04-23 14:20:47

标签: javascript jquery ajax json jsonp

是否可以将数据发布到JsonP?或者所有数据都必须作为GET请求在查询字符串中传递?

我有很多需要发送到服务的数据,跨域,并且它太大而无法通过查询字符串发送

有什么方法可以解决这个问题?

7 个答案:

答案 0 :(得分:81)

由于same origin policy的(非常合理的)限制,无法对另一个域上的服务执行异步POST。 JSON-P仅适用,因为您可以将<script>标签插入DOM中,并且可以指向任何位置。

当然,您可以在另一个域上创建常规表单POST的操作。

修改:如果您愿意花费大量精力插入隐藏的<iframe>并对其属性进行捣乱,那么有一些interesting hacks

答案 1 :(得分:20)

如果需要跨域发送大量数据。我通常创建一个可以分两步调用的服务:

  1. 首先,客户端进行FORM提交(允许发布跨域)。该服务将输入存储在服务器上的会话中(使用GUID作为密钥)。 (客户端创建GUID并将其作为输入的一部分发送)

  2. 然后客户端执行正常的脚本注入(JSONP)作为参数,您使用与FORM帖子中使用的GUID相同的GUID。该服务处理来自会话的输入并以正常的JSONP方式返回数据。在此之后会话被销毁。

  3. 这当然依赖于您编写服务器后端。

答案 2 :(得分:7)

我知道这是严重的死灵法术,但我想我会使用jQuery发布我的JSONP POST实现,我已成功用于我的JS小部件(这用于客户注册和登录):

基本上,我正在使用IFrame方法,如接受的答案所示。我正在做的不同是在发送请求之后,我正在注意,如果可以使用计时器在iframe中访问表单。当无法访问表单时,表示请求已返回。然后,我正在使用普通的JSONP请求来查询操作的状态。

我希望有人发现它有用。在&gt; = 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;
}

答案 3 :(得分:4)

通常,JSONP是通过向调用文档添加<script>标记来实现的,这样JSONP服务的URL就是“src”。浏览器使用HTTP GET事务获取脚本源。

现在,如果您的JSONP服务与您的调用页面位于同一个域中,那么您可以通过简单的$.ajax()调用来拼凑一些内容。如果它不在同一个域中,那么我不确定它是如何可能的。

答案 4 :(得分:0)

您可以使用此CORS Proxy project。它会将所有流量定向到您域上的端点,并将该信息转发到外部域。由于浏览器正在将所有请求注册到同一域,因此我们可以发布JSON。 注意:这也适用于服务器上保存的SSL证书。

答案 5 :(得分:-1)

有一个(黑客)解决方案我已经做了很多次,你可以用JsonP发布。 (您将能够发布表格,大于2000个字符,而不是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');

这样做,你打开你的服务器任何发布请求,你应该通过提供身份或其他东西来重新确保这一点。

使用此方法,您还可以将请求类型从jsonp更改为json,两者都有效,只需设置正确的响应内容类型

<强> JSONP

response.setContentType( "text/javascript; charset=utf-8" );

<强> JSON

response.setContentType( "application/json; charset=utf-8" );

请注意,您的服务器不会再尊重SOP(同源政策),但谁在乎?

答案 6 :(得分:-6)

这是可能的,这是我的解决方案:

在你的javascript中:

jQuery.post("url.php",data).complete(function(data) {
    eval(data.responseText.trim()); 
});
function handleRequest(data){
    ....
}

在你的url.php中:

echo "handleRequest(".$responseData.")";