【问题标题】:Post data to JsonP将数据发布到 JsonP
【发布时间】:2011-02-11 13:25:21
【问题描述】:

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

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

有哪些方法可以解决这个问题?

【问题讨论】:

    标签: javascript jquery ajax json jsonp


    【解决方案1】:

    由于same origin policy 的(相当合理的)限制,不可能对另一个域上的服务执行异步POST。 JSON-P 之所以有效,是因为您可以在 DOM 中插入<script> 标签,并且它们可以指向任何地方。

    当然,您可以将另一个域上的页面设置为常规表单 POST 的操作。

    编辑:如果您愿意花很多精力插入隐藏的<iframe>s 并处理它们的属性,那么就有一些interesting hacks

    【讨论】:

    • 您提到“异步 POST”是不可能的......那我可以做一个同步 POST 吗?
    • @mark "同步 POST" 表示提交使用
      的表单
    • 这并不完全正确。您当然可以向其他域发出POST 请求,只要该域和您的浏览器都支持CORS。但是POSTJSONP不兼容是完全正确的。
    • JSONP 是通过插入指向另一个域的<script> 标签来实现的。在浏览器中执行 POST 请求的唯一方法是通过 HTML 表单或 XMLHttpRequest。
    • (一般 - )可以(!)对另一个域上的服务进行异步 POST。限制在于响应。限制也在于 JSONP 请求。
    【解决方案2】:

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

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

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

    这当然取决于您编写服务器后端。

    【讨论】:

    • 试过你的方法。适用于 FF14 和 Chrome20。 Opera11 和 IE9 只是没有转帖。 (用他们的调试工具检查并在另一端的服务器上收听)可能与IE的残疾有关的是这个问题:stackoverflow.com/questions/10395803/…控制台中的Chrome投诉,但仍然做了POST:XMLHttpRequest无法加载localhost:8080/xxxOrigin null Access-Control-Allow-Origin 不允许。
    • @OneWorld — 你没有按照答案所说的去做。 XMLHttpRequest 根本不应该参与其中。 Per 的回答使用常规表单提交来发出 POST 请求,然后使用脚本元素注入来发出 GET 请求。
    【解决方案3】:

    我知道这是严重的死灵法,但我想我会使用 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;
    }
    

    【讨论】:

      【解决方案4】:

      一般来说JSONP是通过在调用文档中添加&lt;script&gt;标签来实现的,这样JSONP服务的URL就是“src”。浏览器通过 HTTP GET 事务获取脚本源。

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

      【讨论】:

      • 在这种情况下它不在同一个域中。我假设只有 GET 是可能的,但我想检查一下,因为我今天才开始阅读 JsonP,需要就它是否适合我的需要做出一些决定
      • 如果不在同一个域但支持CORS,那么只要浏览器也支持就可以。在这些情况下,您将使用普通的JSON 而不是JSONP
      • 是的,@hippietrail 2 年有很大的不同 :-) CORS 确实使这成为可能,但当然它确实需要适当地设置数据源。
      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        有一个(hack)解决方案我已经做过很多次了,你将能够使用 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');
        

        这样做,您正在向任何发布请求打开服务器,您应该通过提供 ident 或其他内容来重新保护它。

        通过这个方法,你也可以将请求类型从jsonp更改为json,两者都可以,只需设置正确的响应内容类型

        jsonp

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

        json

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

        请注意,您的服务器将不再遵守 SOP(同源政策),但谁在乎呢?

        【讨论】:

        • 这不是带有 CORS 的 AJAX。 AJAX 意味着您正在使用 XML。这是带有 CORS 的 JSON[P]。 JSONP 是带有“填充”的“JSON”。如果它正在发送 JSON 数据,并用函数调用进行填充,那么它就是带有 CORS 的 JSONP。除了将 &lt;script&gt; 标签注入 HTML DOM 之外,您还可以使用 JSON 和 JSONP 数据表示法(哎呀,您甚至可以在桌面应用程序中使用它们,假设您想向同一服务器发出多个 JSON 请求,并且想要使用例如,函数名称作为请求跟踪 ID)。
        【解决方案7】:

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

        在您的 javascript 中:

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

        在你的 url.php 中:

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

        【讨论】:

        • 在这种情况下,jQuery 很可能根据他们的文档将您的请求转换为 Get:注意:这会将 POST 转换为远程域请求的 GET。 api.jquery.com/jQuery.ajax
        猜你喜欢
        • 2011-05-12
        • 1970-01-01
        • 2013-01-02
        • 1970-01-01
        • 1970-01-01
        • 2018-11-27
        • 2013-09-26
        • 1970-01-01
        相关资源
        最近更新 更多