前戏

  • 写的很详细了,应该很好懂。
  • 注:文中代码均是截取的代码片段,仅供参考和理解,酌情复制。

正文

同源策略

同源策略规定只在协议相同、域名相同、端口相同的情况下,也就是两个网页同源时,才能读写对方的资源。这是为了保证用户的信息安全做出的限制,然而同源策略有时也会对合理的用途造成影响,那么就需要想办法规避同源策略带来的影响。

用script标签发请求

浏览器解析html页面时,如果看到有如link、img、script等标签时,就会自动向标签对应路径发起一个get请求以获取想要得到的资源。而用标签发起的请求是不受同源策略限制的,利用这种特性,就可以达到规避同源策略向目标网站发起请求的目的。

例如,页面中有一个script标签:

<script src="http://demo.com/test"></script>
复制代码

这个标签就会向 demo.com 下的 test 路径发起请求,而当服务器接收到请求后就会做出响应。当然一般这种标签是通过JavaScript来动态创建的:

const script = document.createElement('script')
script.src = 'http://demo.com/test'
document.body.appendChild(script)
复制代码

这样就能直接用js动态地发送请求了。需要注意的是,因为请求是通过script发送的,所以浏览器接收到响应时会立即执行请求到的结果。例如:

...
if (pathNoQuery === '/test') {response.setHeader('Content-Type', 'application/javascript')response.write('alert('这是 test 路径返回的结果。')')
} else {response.statusCode = 404
}
response.end()
...
复制代码

这里服务器接收到请求后返回了 alert(...) 的代码,浏览器接收到结果后就会执行 alert(...),也就会弹出一个提示框。利用这一点,就可以直接在接收到的script标签中使用得到的数据。假设页面中就一个id为balanceText的元素用来显示用户的余额,服务器通过getResultFromDb函数来获取数据库中的数据:

...
if (pathNoQuery === '/test') {const rs = getResultFromDb()response.setHeader('Content-Type', 'application/javascript')response.write(`balanceText.textContent = '你还有${rs.balance}块钱'`)
} else {response.statusCode = 404
}
response.end()
...
复制代码

这样每次向服务器请求时,服务器就会取得数据库中的数据并返回更改对应元素文本的执行语句,浏览器接收响应后执行语句,即可在页面中显示出接收到的数据。

然而这种方法很令人困惑,展示数据明明应该是前端应该做的事,却被后端做了。而且后端为了展示数据还需要了解前端的页面结构。而这也导致后端与前端的耦合度太高,后端的响应几乎只能为这一个页面服务。

那么解决这个问题的思路自然是降低前后端的耦合度,也就是解耦。前端的代码就应该放到前端去写,而后端只需要将数据交给前端就好,不需要做额外的事情。

回调函数

解决的办法是在前端代码中定义一个函数,也就是所谓的回调函数。服务器返回的代码中只需要执行这个函数,而前端想要获取的数据只需要通过参数传递到这个函数中即可。这里就可以修改一下之前的代码:

前端:

const cbFunc = (result) => {balanceText.textContent = `你还有${result}块钱`
}
const jsonpScript = document.createElement('script')
jsonpScript.src = 'http://demo.com/test?callback=cbFunc'
document.body.appendChild(jsonpScript)
复制代码

后端:

...
if (pathNoQuery === '/test') {const rs = getResultFromDb()response.setHeader('Content-Type', 'application/javascript')response.write(`${queryObject.callback}(${rs.balance})`)
} else {response.statusCode = 404
}
response.end()
...
复制代码

这里前端请求时在查询参数中传递了一个callback参数,记录回调函数的函数名。后端只需要使用这个函数名返回一个调用回调函数的语句就好了。与此同时请求的数据也作为参数被传递回给回调函数,接着只需要在回调函数中使用这个参数就可以得到想要的数据了。这样后端就只需要专注于返回数据而无需操心前端的代码,前端拿到数据也就可以放心地为所欲为了。

JSONP

那么至此为止,上文说了这么多,和JSONP有什么关系?

在这里总结一下:

  1. 动态创建地创建script标签以发起请求,在src中填写请求的目标路径,并传入查询参数callback也就是回调函数的函数名。
  2. 服务器接收到请求时,会根据查询参数callback返回执行回调函数的语句,并在参数传入请求方想要的数据。
  3. 请求方接收到响应后就会执行这个语句也就是执行回调函数,这样请求方就能在回调函数中取得想要的数据。

这个请求的过程就是JSONP。

结语

  • 所以说JSONP和JSON其实没啥关系,只是JSONP一般用来传输JSON。
  • JSONP和AJAX也没什么关系。
  • JSONP不能发起POST请求,因为script标签本身无法发POST请求。

简单理解JSONP的定义及其实现相关推荐

  1. 【转载】Deep learning:十九(RBM简单理解)

    Deep learning:十九(RBM简单理解) 这篇博客主要用来简单介绍下RBM网络,因为deep learning中的一个重要网络结构DBN就可以由RBM网络叠加而成,所以对RBM的理解有利于我 ...

  2. c语言理解参数,c语言中对可变参数列表的简单理解

    函数原型中一般情况下参数的数目是固定的,但是如果想在不同的时候接收不定数目的参数时该怎么办呢?c语言提供了可变参数列表来实现. 可变参数列表是通过宏来实现的,这些宏定义在stdarg.h的头文件中.头 ...

  3. JS闭包的简单理解。优缺点以及垃圾回收机制

    闭包是什么? ·了解闭包首先了解js的'链式作用域'结构,对象可以一级一级的向上查找父对象的变量,所以父对象的变量对子对象可见,反之不成立:所以都可以访问全局变量 ·为了解决函数外部无法访问函数内局部 ...

  4. php _call call_user_func_array,PHP call_user_func和call_user_func_array函数的简单理解与应用分析...

    本文实例讲述了PHP call_user_func和call_user_func_array函数的简单理解与应用.分享给大家供大家参考,具体如下: call_user_func():调用一个回调函数处 ...

  5. vue函数如何调用其他函数?_编程|如何简单理解函数的传参、返回、调用

    1 函数内部变量的局部性 在一个函数中定义的变量(包括实参),其作用域仅限于定义它的函数中,在其它的函数不能使用,这种变量称为"局部变量". 局部变量的作用域:函数内部声明和定义的 ...

  6. 对CMMI标准的简单理解

    CMMI用于帮助软件企业对软件工程的整个过程进行管理和改进,从而能按时.不超预算地开发出高质量地软件. CMMI全称为"Capability Maturity Model Integrati ...

  7. 关于C语言函数的简单理解

    关于C语言函数的简单理解 C语言中的函数 在C语言中,函数是构成程序的基本模块.程序的执行从main()函数的入口开始,到main()函数的出口结束,中间循环.往复.迭代的调用一个有一个函数.每个函数 ...

  8. CPD配准算法及代码的简单理解(Coherent Point Drift)

    我的毕业设计用到了CPD算法,以及CPD代码工具包,当时刚开始接触CPD时在网上没找到几篇教程或是经验总结的东西.现在毕设做完了,就结合我的理解写一篇文章.可能写的会有点乱,因为我也是一时兴起想要做一 ...

  9. Python实现股票量化交易学习进阶(二)之简单交易策略的定义实现

    Python实现股票量化交易学习进阶第二篇之简单交易策略的定义实现 1.backtrader回测框架知识 2.需求一自定义MACD指标 3.需求二自定义实现KDJ指标 4.需求三自定义CCI指标 1. ...

最新文章

  1. nagios配置监控的一些思路和工作流程
  2. UFS和eMMC闪存差异在哪?
  3. Scala AKKA入门示例
  4. 怎么画单极交流放大电路波形图_珠海放大IC怎么样
  5. 于iOS跳转到应用程序AppStore
  6. C ++ 数组 | 寻找最大、最小值,数组(Array)_1
  7. [Git] Ubuntu 上更新 git
  8. 2000,XP中显示器和系统匹配的问题?
  9. 数学建模综合评价方法
  10. 小米手机连接电脑只能看到部分相片_小米手机连接电脑后怎么看照片?
  11. 冰川时代4中英台词全集
  12. 张飞实战电子1-31部 和硬件工程师90天学习资料及笔记汇总
  13. 随机函数(随机取数)
  14. oracle 行转列后列名,Oracle 多行转多列,列值转为列名
  15. 萨克斯《全球视角的宏观经济学》课后答案
  16. 怎样对比计算机配置,怎么看电脑配置好坏,教您怎么看电脑配置好坏
  17. 如何从iCloud中下载元气骑士存档
  18. 可以与eclipse媲美的开源油藏数值模拟器OPM/Flow的安装及使用
  19. Unity应用自带UGUI与EPPlus库制作自制Excel(.xlsx)操作程序
  20. 计算机属性无法查看无反应,Win7旗舰版右键查看计算机属性未反应的处理方法...

热门文章

  1. python模块request怎么安装_安装 request模块
  2. bootstrap 按钮样式单选效果_【20201117】Bootstrap前端框架学习笔记
  3. 大学计算机专业全民,计算机专业大学排名实力顺序(上大学国内计算机专业大学哪个好值得报读)...
  4. 类写了package java命令出错_java/javac命令行如何同时引用多个包;错误 TypeError: 'JavaPackage' object is not callable 的含义...
  5. angular 注入器配置_注入器和发布库–AngularJS学习笔记(三)
  6. delphi php 加密解密_如何恢复被MaMoCrypt勒索软件加密的数据
  7. 大数据项目开发案例_大数据开发相关术语解析
  8. 订餐系统项目中OrderForm、OrderDTO、OrderMaster和ResultVO的区别
  9. 《天天数学》连载50:二月十九日
  10. 【BZOJ1758】重建计划,点分治+单调队列