将 PUT/POST/DELETE 与 JSONP 和 jQuery 结合使用

2024-04-13

我正在致力于创建一个支持跨域请求、JSON/JSONP 支持和主要 HTTP 方法 (PUT/GET/POST/DELETE) 的 RESTful API。现在,虽然通过服务器端代码可以轻松访问此 API,但最好将其公开给 JavaScript。据我所知,当使用 jQuery 执行 JSONP 请求时,它仅支持 GET 方法。有没有办法使用 POST/PUT/DELETE 执行 JSONP 请求?

理想情况下,我想要一种从 jQuery 内部执行此操作的方法(如果核心不支持此功能,则通过插件),但我也会采用简单的 javascript 解决方案。任何指向工作代码或如何编码的链接都会很有帮助,谢谢。


实际上 - 有一种方法可以支持 POST 请求。 并且不需要代理服务器 - 只需要一个小型实用 HTML 页面,如下所述。

以下是如何有效地进行 POST 跨域调用,包括附加文件、多部分和全部:)

首先是以下步骤理解想法,之后 - 找到一个实现示例。

jQuery的JSONP是如何实现的,为什么不支持POST请求?

虽然传统的 JSONP 是通过创建脚本元素并将其附加到 DOM 中来实现的,但结果会迫使浏览器触发 HTTP 请求来检索标签的源,然后将其作为 JavaScript 执行,即浏览器触发的 HTTP 请求很简单 GET。

什么不限于 GET 请求?

表单。提交表格时指定action跨域服务器。 可以完全使用脚本创建 FORM 标记,使用脚本填充所有字段,设置所有必要的属性,注入 DOM,然后提交 - 全部使用脚本。

但是我们怎样才能在不刷新页面的情况下提交FORM呢?

我们指定target表单到同一页面中的 IFRAME。 还可以使用脚本创建、设置、命名 IFRAME 并将其注入到 DOM。

但是我们如何才能向用户隐藏这项工作呢?我们将使用以下方法将 FORM 和 IFRAME 包含在隐藏的 DIV 中style="display:none"

(这是该技术中最复杂的部分,请耐心等待)

但是来自另一个域的 IFRAME 无法对其顶级文档调用回调。如何克服呢?

事实上,如果 FORM 提交的响应是来自另一个域的页面,则顶级页面和 IFRAME 中的页面之间的任何脚本通信都会导致“访问被拒绝”。所以服务器无法使用脚本回调。服务器能做什么?redirect。服务器可以重定向到任何页面 - 包括与顶级文档相同域中的页面 - 可以为我们调用回调的页面。

服务器如何重定向?

两种方式:

  1. 使用客户端脚本,例如<Script>location.href = 'some-url'</script>
  2. 使用 HTTP 标头。看:http://www.webconfs.com/how-to-redirect-a-webpage.php http://www.webconfs.com/how-to-redirect-a-webpage.php

那么我最终会得到另一页吗?它对我有什么帮助?

这是一个简单的实用程序页面,将在所有跨域调用中使用。实际上,这个页面实际上是一种代理,但它不是服务器,而是一个简单的静态 HTML 页面,任何拥有记事本和浏览器的人都可以使用。

该页面所需要做的就是使用来自服务器的响应数据调用顶级文档上的回调。客户端脚本可以访问所有 URL 部分,并且服务器可以将其响应编码为其中的一部分,以及必须调用的回调的名称。意味着 - 该页面可以是静态页面和 HTML 页面,并且不必是动态服务器端页面:)

该实用程序页面将从它运行的 URL 中获取信息 - 特别是在下面的我的实现中 - 查询字符串参数(或者您可以使用锚 ID 编写自己的实现 - 即“#”右侧的 url 部分)符号)。由于此页面是静态的 - 甚至可以允许对其进行缓存:)

为每个 POST 请求添加 DIV、SCRIPT 和 IFRAME 最终不会泄漏内存吗?

如果您将其留在页面中 - 就会的。如果你在你之后清理 - 它不会。我们所要做的就是为 DIV 提供一个 ID,每当服务器响应到达或超时时,我们就可以使用该 ID 来删除 DIV 以及其中的 FORM 和 IFRAME。

我们得到什么?

有效地进行 POST 跨域调用,包括附加文件、多部分和全部:)

有什么限制?

  • 服务器响应仅限于适合重定向的任何内容。
  • 服务器必须始终向 POST 请求返回 REDIRECT。其中包括 404 和 500 错误。 或者 - 在触发请求之前在客户端上创建一个超时,这样您就有机会检测尚未返回的请求。
  • 并不是每个人都能理解这一切以及所涉及的所有阶段。这是一种基础设施级别的工作,但是一旦你让它运行起来 - 它就会很震撼:)

我可以将其用于 PUT 和 DELETE 调用吗?

FORM 标签不进行 PUT 和 DELETE。 但这总比什么都没有好:)

好的,明白了概念。技术上是如何做到的?

我所做的是:

我创建了 DIV,将其设置为不可见,并将其附加到 DOM。我还给它一个 ID,我可以在服务器响应到达后从 DOM 中清理它(就像 JQuery 清理它的 JSONP SCRIPT 任务一样 - 但 DIV)。

Then I compose包含 IFRAME 和 FORM 的字符串 - 具有所有属性、属性和输入字段,并将其注入到不可见的 DIV 中。仅当 div 位于 DOM 中之后才将此字符串注入 DIV 中,这一点很重要。如果没有 - 它不会在所有浏览器上运行。

之后 - 我获取表格参考并提交。 只需记住之前的一行 - 设置一个超时回调如果服务器没有响应或以错误的方式响应。

回调函数包含清理代码。在响应超时的情况下,它也会被计时器调用(并在服务器响应到达时清除其超时计时器)。

显示代码!

下面的代码片段在“纯”javascript 上是完全“中性”的,并声明了它需要的任何实用程序。只是为了简化解释这个想法 - 它都在全局范围内运行,但是它应该更复杂一点......

尽可能将其组织在函数中,并参数化您需要的内容 - 但请确保需要相互查看的所有部分都在同一范围内运行:)

对于此示例 - 假设客户端运行在http://samedomain.com http://samedomain.com服务器运行在http://crossdomain.com http://crossdomain.com.

顶层文档中的脚本代码

//declare the Async-call callback function on the global scope
function myAsyncJSONPCallback(data){
    //clean up 
    var e = document.getElementById(id);
    if (e) e.parentNode.removeChild(e);
    clearTimeout(timeout);

    if (data && data.error){
        //handle errors & TIMEOUTS
        //...
        return;
    }

    //use data
    //...
}

var serverUrl          = "http://crossdomain.com/server/page"
  , params = { param1  : "value of param 1"      //I assume this value to be passed
             , param2  : "value of param 2"      //here I just declare it...
             , callback: "myAsyncJSONPCallback" 
             }
  , clientUtilityUrl   = "http://samedomain.com/utils/postResponse.html"
  , id     = "some-unique-id"// unique Request ID. You can generate it your own way
  , div    = document.createElement("DIV")       //this is where the actual work start!
  , HTML   = [ "<IFRAME name='ifr_",id,"'></IFRAME>"  
             , "<form target='ifr_",id,"' method='POST' action='",serverUrl 
             , "' id='frm_",id,"' enctype='multipart/form-data'>"
             ]
  , each, pval, timeout;

//augment utility func to make the array a "StringBuffer" - see usage bellow
HTML.add = function(){
              for (var i =0; i < arguments.length; i++) 
                  this[this.length] = arguments[i];
           }

//add rurl to the params object - part of infrastructure work
params.rurl = clientUtilityUrl //ABSOLUTE URL to the utility page must be on
                               //the SAME DOMAIN as page that makes the request

//add all params to composed string of FORM and IFRAME inside the FORM tag  
for(each in params){
    pval = params[each].toString().replace(/\"/g,"&quot;");//assure: that " mark will not break
    HTML.add("<input name='",each,"' value='",pval,"'/>"); //        the composed string      
}
//close FORM tag in composed string and put all parts together
HTML.add("</form>");
HTML = HTML.join("");   //Now the composed HTML string ready :)

//prepare the DIV
div.id = id; // this ID is used to clean-up once the response has come, or timeout is detected
div.style.display = "none"; //assure the DIV will not influence UI

//TRICKY: append the DIV to the DOM and *ONLY THEN* inject the HTML in it
//        for some reason it works in all browsers only this way. Injecting the DIV as part 
//        of a composed string did not always work for me
document.body.appendChild(div);
div.innerHTML = HTML;

//TRICKY: note that myAsyncJSONPCallback must see the 'timeout' variable
timeout = setTimeout("myAsyncJSONPCallback({error:'TIMEOUT'})",4000);
document.getElementById("frm_"+id+).submit();

跨域的服务器来自服务器的响应预计是重定向,通过 HTTP 标头或通过编写 SCRIPT 标记。 (重定向更好,SCRIPT标签更容易用JS断点调试)。 这是标题的示例,假设rurl上面的值

Location: http://samedomain.com/HTML/page?callback=myAsyncJSONPCallback&data=whatever_the_server_has_to_return

注意

  • 的价值data参数可以是 JavaScript 对象字面量或 JSON 表达式,但最好是 url 编码的。
  • 服务器响应的长度仅限于浏览器可以处理的 URL 长度。

另外 - 在我的系统中,服务器有一个默认值rurl所以这个参数是可选的。但只有当客户端应用程序和服务器应用程序耦合时才能做到这一点。

发出重定向标头的 API:

http://www.webconfs.com/how-to-redirect-a-webpage.php http://www.webconfs.com/how-to-redirect-a-webpage.php

或者,您可以让服务器写入以下内容作为响应:

<script>
   location.href="http://samedomain.com/HTML/page?callback=myAsyncJSONPCallback&data=whatever_the_server_has_to_return"
</script>

但 HTTP-Headers 会被认为更干净;)

与顶级文档位于同一域的实用程序页面

我使用与以下相同的实用程序页面rurl对于我所有的发布请求:它所做的就是使用客户端代码从查询字符串中获取回调的名称和参数,并在父文档上调用它。它可以做到ONLY当此页面在与触发请求的页面完全相同的域中运行时!重要的:与 cookie 不同 - 子域不算在内!它必须具有完全相同的域。

如果此实用程序页面不包含对其他资源(包括 JS 库)的引用,也会使其更加高效。所以这个页面是纯 JavaScript。但您可以随心所欲地实施它。

这是我使用的响应者页面,其 URL 可以在rurlPOST 请求(在示例中:http://samedomain.com/utils/postResponse.html http://samedomain.com/utils/postResponse.html )

<html><head>
<script type="text/javascript">
//parse and organize all QS parameters in a more comfortable way
var params = {};
if (location.search.length > 1) {
    var i, arr = location.search.substr(1).split("&");
    for (i = 0; i < arr.length; i++) {
        arr[i] = arr[i].split("=");
        params[arr[i][0]] = unescape(arr[i][1]);
    }
}

//support server answer as JavaScript Object-Literals or JSON:
//  evaluate the data expression
try { 
    eval("params.data = " + params.data); 
} catch (e) { 
    params.data = {error: "server response failed with evaluation error: " + e.message
                  ,data : params.data
                  }
}

//invoke the callback on the parent
try{
     window.parent[ params.callback ](params.data || "no-data-returned");
}catch(e){
     //if something went wrong - at least let's learn about it in the
     //      console (in addition to the timeout)
     throw "Problem in passing POST response to host page: \n\n" + e.message;
}
</script>
</head><body></body></html>

它不像 jQuery 那样自动化和“现成”库,并且涉及一些“手动”工作 - 但它有魅力:)

如果您是现成库的狂热粉丝 - 您还可以查看道场工具包当我上次检查时(大约一年前)——他们有自己的相同机制的实现。http://dojotoolkit.org/ http://dojotoolkit.org/

祝你好运,朋友,希望对你有帮助...

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 PUT/POST/DELETE 与 JSONP 和 jQuery 结合使用 的相关文章

  • Flask wtf.quick_form 运行一些 javascript 并设置表单变量

    我正在创建博客文章 到目前为止已经使用普通的 html 表单完成了 我所做的一个有趣的想法是运行 javascript onclick 并使用页面中的额外数据在表单中设置一个隐藏变量 这很好地传递到服务器并通过 request form 获
  • 响应式网格布局框架[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 保存/导出Chrome的JavaScript控制台输入历史记录

    无论如何 我可以保存或导出 JavaScript 控制台的历史记录吗 input 控制台历史记录 在 Google Chrome 中 我不想保存输出或错误 因此将鼠标悬停在控制台框上 右键单击并选择Save as 不是解决方案 我不想每次都
  • 如何使用 jQuery 向表中添加新行,并为其分配递增的 id

    我有一个现有的 HTML 表格 它是用户输入 GPS 点的表单的一部分 用户还可以选择上传 GPS 数据点 我想要一个用户可以按下的按钮 其中一些 Javascript 会向表中添加一个或多个新行 但新行必须继续增加表中使用的名称和 id
  • AJAX:检查字符串是否为 JSON?

    我的 JavaScript 有时会在这一行崩溃 var json eval this responseText 当争论时会导致崩溃eval 不是 JSON 在进行此调用之前有什么方法可以检查字符串是否为 JSON 我不想使用框架 有什么方法
  • KeyboardEvent.keyCode 已弃用。这在实践中意味着什么?

    根据 MDN 我们绝对应该not正在使用 keyCode财产 它已被弃用 https developer mozilla org en US docs Web API KeyboardEvent keyCode https develope
  • 如何清除WebGL中的矩形区域?

    WebGL 有一个clear清除整个表面的方法 清除表面的特定矩形的最佳方法是什么 例如 我想将一个从 50 50 开始的 100x100 像素框设置为全零 ARGB 0 0 0 0 我现在能想到的就是用一个写入零的片段着色器绘制一个四边形
  • Flux + React.js - 操作中的回调是好还是坏?

    让我解释一下我最近遇到的问题 我有 React js Flux 驱动的应用程序 有一个列表显示文章数量 注意 应用程序中有多个不同的列表 和文章详情查看在里面 但每个列表只有一个 API 端点 它返回文章数组 为了显示我需要的详细信息fin
  • 使水平滚动条始终可见,即使底部不在视图中

    我将用一个片段来开始这个问题 该片段几乎显示了我想要完成的任务 wrapper overflow hidden display flex sidebar min width 200px background 333 color FFF co
  • 如何访问另一个 mobx 商店中的 mobx 商店?

    假设以下结构 stores RouterStore js UserStore js index js each of Store jsfiles 是一个 mobx 存储类 包含 observable and action index js只
  • Keycloak javascript 适配器 `keycloak.init` 加载 404 iframe

    我正在尝试使用 javascript 适配器将 Keycloak 集成到我的客户端应用程序keycloak js 但是 我似乎无法让它发挥作用 这是我的代码 const keycloak new Keycloak realm my real
  • 如何在 e2e AngularJS 测试中进行文件上传?

    在我的一种观点中 我有一个文件上传控件 它支持通过拖放或单击按钮后打开的标准文件对话框上传文件 How to do this in my e2e tests1 1 Just one of the two options will be en
  • 有关于 PHP 中的 V8JS 的文档吗?

    有没有关于V8JS的文档 我是否只需要标准 PHP 或一些扩展即可使用 V8JS 我将非常感谢有关 PHP 中的 V8JS 的任何信息 要求 PHP 5 3 3 和 V8 库和标头安装在正确的路径中 Install http www php
  • window.showModalDialog 的等效跨浏览器解决方案是什么?

    window showModalDialog 的等效跨浏览器解决方案有哪些 showModalDialog 在 IE 和 FF 3 中引入 我个人认为没有 但是有很多 UI 工具包提供了这样的功能 例如jQuery UI http jque
  • rabbitmq 的 REST API

    有没有办法从 ajax 向 RabbitMQ 发送数据 我的应用程序由数千个 Web 客户端 用 js 编写 和 WCF REST 服务组成 现在我试图弄清楚如何为我的应用程序创建可扩展点 这个想法是有一个rabbitmq实例 它从放置在一
  • 加载另一个 JS 脚本后加载

    这是我的代码 very big js file lots of html stuff 问题是 这些是异步加载的 有没有办法等待第二个脚本直到第一个脚本加载 如果您使用 jQuery 有一个非常简单的方法可以通过获取脚本 https api
  • 需要js、d3 和 nvd3 集成

    我面临整合的问题要求 questions tagged requirejs with d3 questions tagged d3 and nvd3 questions tagged nvd3 我找到了一个使用 require 的简单解决方
  • Fancybox 画廊组

    我正在使用 fancyboxhttp fancyapps com fancybox http fancyapps com fancybox 我的问题是 我可以将不同的资源组合在一起吗 我的意思是同一画廊 或 组 中带有内嵌或视频的图像 如果
  • 有没有非常轻的灯箱? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 我可以使用 jQuery 动态创建文件(及其内容)吗? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 这是我的 HTML 代码 ul li

随机推荐

  • ASP.Net双击问题

    我的 ASP net 页面有一个小问题 如果用户双击 提交 按钮 它将写入数据库两次 即在图像按钮上执行两次 onclick 方法 如何才能使用户单击图像按钮时仅禁用图像按钮 我试过了
  • NSPredicate 过滤 Realm 和 block 的区别

    我想知道 Realm 的查询性能 鉴于此代码 let result1 realm objects Person self filter age lt 30 AND AND let result2 realm objects Person s
  • 如何使用正则表达式匹配括号内的文本?

    我有以下模式 COMPANY 277 9887 ASP 277 9887 INC 我希望最终的输出是 公司 ASP INC 目前我有以下代码 它不断返回原始模式 我假设因为该组都落在第一个 和最后一个 之间 Pattern p Patter
  • C# 类 Java 的内联扩展?

    我会在 Google MSDN 上查找此内容 但我不知道它叫什么 所以我在这里询问 在 Java 中 我似乎记得你可以做这样非常酷的事情 例如 Class MyClass int number MyClass void setNumber
  • XCode 机器人错误:“内部时间序列后错误”

    我已经设置了新的 OSX Mavericks 服务器来通过机器人运行我的 iOS 项目的测试 虽然构建和运行测试以及一切都顺利进行 但实际的集成被报告为失败 在机器人日志文件末尾 以下错误多次出现 https Request XCBotSe
  • 还有其他访问相机的替代方法吗?

    除了使用 ActionScript 3 之外 还有其他方法来访问相机吗 import flash media Camera videoInstance attachCamera cameraInstance 或者我应该使用任何 API 吗
  • VBA 控件集合(数组?)

    在寻找一种在用户表单上模拟可填充网格的方法时 我遇到了这在 Excel 先生身上 https www mrexcel com board threads datagrid on vba userform 840043 site Dim Gr
  • 解决 CouchDB 中已删除文档的复制冲突

    官方文档推荐的解决复制冲突的方式是 使用文档阅读冲突的修订版本 conflicts字段 例如通过视图 获取列出的所有修订的文档 执行特定于应用程序的合并 删除不需要的修订 当我想合并的时候问题就来了deleted文件 他们没有出现在 con
  • Angular 6 如何获取两个位置 AGM 之间的距离

    I get 方向使用此参考在两点之间https www npmjs com package agm direction https www npmjs com package agm direction现在我想获取 计算distance在两
  • C# 和不同国家的当前当地时间

    C 提供了一种获取当前日期的方法DateTime Now 但问题是我的服务器在美国 当我使用时我得到美国时间DateTime Now 由于我的用户来自世界各地 有什么方法可以在 C 中获取特定国家 地区的当前当地时间吗 我有每个用户的区域设
  • 设置为 html 文档的背景

    有没有办法让我制作一个 HTML5 画布作为我正在制作的网页的背景 并将所有元素放在它上面 所以它的作用就像 我尝试使用 z index 执行此操作并将元素定位在顶部 但随后它们是可单击或可聚焦的 我需要它们仍然正常工作 但画布也只能在背景
  • 使用 PDFBox 将 FormXobject 内容从资源添加到内容流?

    我的 page1 gt Resource gt Xobjects gt Fm0 Fm1 Fm2 下有 FormXobject 所以它不是直接内容流 在内容 gt 内容流下不可用 所以我想将 Fm0 gt Contentstream 的内容流
  • Android Studio 1.3.1 和 Google Glass -- 创建新项目 |目标 Android 设备 |玻璃未安装

    当尝试在 Android Studio 1 3 1 Win 8 1 中创建新项目时 我无法选择 Glass 在 上目标 Android 设备 屏幕 Glass SDK 不可选 已禁用 并显示 Glass 未安装 但是 当我检查 SDK 管理
  • 如何避免来自mongodb的transparent_hugepage/defrag警告?

    我从 mongodb 收到以下关于 THP 的警告 2015 03 06T21 01 15 526 0800 I CONTROL initandlisten WARNING sys kernel mm transparent hugepag
  • Selenium C# 中的显式等待不起作用。怎么了?

    所以我遇到了显式等待的问题 我不想使用 Thread Sleep 这是一个简单的测试 它打开一个页面 然后后退和前进 加载此页面大约需要 2 3 秒 我想以动态方式执行此操作 测试 希望我不要太困惑 我做了很多研究 但没有任何作用 也许我做
  • Delphi从ios/Android本地存储打开PDF

    我尝试在移动设备上从本地存储打开 PDF 文件 我已将文件放入 iOS 的启动 文档 Android 的资产 内部 用这个代码 filename TPath Combine TPath GetDocumentsPath file pdf W
  • 记忆 SQL 查询

    假设我有一个运行 SQL 查询并返回数据帧的函数 import pandas io sql as psql import sqlalchemy query string select a from table def run my quer
  • Groovy 字符串连接

    当前代码 row column each column gt println column attributes name println column value Column is a Node具有单个属性和单个值 我正在解析 xml
  • iOS13:如何检测状态栏点击事件?

    在我的 appDelegate 中 我覆盖touchesBegan检测何时单击状态栏 void touchesBegan NSSet touches withEvent UIEvent event super touchesBegan to
  • 将 PUT/POST/DELETE 与 JSONP 和 jQuery 结合使用

    我正在致力于创建一个支持跨域请求 JSON JSONP 支持和主要 HTTP 方法 PUT GET POST DELETE 的 RESTful API 现在 虽然通过服务器端代码可以轻松访问此 API 但最好将其公开给 JavaScript