欢迎学习交流!!!
持续更新中…

文章目录

  • 同源政策
  • 跨域问题
    • JSONP
      • JSONP代码优化
    • CORS

同源政策

如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。

同源政策的目的:
同源政策是为了保护用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指A网站在客户端设置的Cookie,B网站是不能访问的
随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax请求,如果请求,浏览器就会报错。

跨域问题

JSONP

使用JSONP解决同源限制问题,该方式实际上已经不属于ajax请求的范围,但是可以模拟出ajax的请求效果,该方式就是绕过浏览器的同源政策限制,向非同源服务器端发送请求
jsonp是json with padding的缩写(实际上指在服务器端将json数据作为填充内容/函数的参数,将json数据填充到函数中去),它不属于Ajax请求,但它可以模拟Ajax请求

使用JSONP解决同源限制问题的基本步骤

  1. 将不同源的服务器端请求地址写在script标签的src属性中(该标签的src属性不受同源政策的限制)
<script src="www.example.com"></script>
//请求地址可以是任意形式,不是必须以.js结尾的,但必须返回合法的js代码

可以利用script的src属性中可以写线上的jquery文件地址,为典型的向非同源的服务器端请求数据的案例。

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  1. 服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。在服务器端这段响应的代码必须是字符串,字符串中包括函数调用的代码。因为如果不是字符串,就是真正的函数调用,而这段函数调用就会在服务器端执行,就不会在客户端执行。需要注意的是,函数是在客户端被调用的,所以需要在定义之前在客户端准备好函数的定义,因为只有定义了这个函数,函数才能够被调用起来(第3步)。
const data = 'fn({name: "张三", age: "17"})';
res.send(data);
  1. 在客户端全局作用域下定义函数fn(必须写在script标签之上,这样才能在执行函数的时候找到函数定义),在定义过程中用的是形参,可以将形参和实参相对应
function fn (data) {  }
  1. 在fn函数内部对服务器端返回的数据进行处理
function fn (data) { console.log(data); }

例:
客户端:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- 要在请求地址之前就将函数定义好 -->
<script>function fn() {console.log('客户端的fn函数被调用了')}</script><!-- 1. 将非同源服务器端的请求地址写在script标签的src属性中 -->
<script src="http://localhost:3001/test"></script>
</body>
</html>

在另外一个,3001服务器中的app.js文件:

<!-- 2号服务器的app.js -->
<script>
// 引入express框架
const express = require('express');
// 路径处理模块
const path = require('path');
// 创建网站服务器
const app = express();
app.use(express.static(path.join(__dirname, 'public')));app.get('/test',(req, res) => {//函数调用应该在服务器端进行调用,只需要服务器端写出函数调用的字符串,若在此处直接调用,则前后没有函数定义的代码,就会报错const result = 'fn()'; res.send(result)
})
</script>

JSONP优点

  • XMLHttpRequest 对象实现 Ajax 请求那样受到同源策略的限制
  • 兼容性很好,在古老的浏览器也能很好的运行
  • 不需要 XMLHttpRequest 或 ActiveX 的支持;并且在请求完毕后可以通过调用 callback 的方式回传结果。
    JSONP缺点
  • 它支持 GET 请求而不支持 POST 等其它类行的 HTTP 请求。
  • 只支持跨域 HTTP 请求这种情况,不能解决不同域的两个页面或 iframe 之间进行数据通信的问题

JSONP代码优化

虽然现在请求能够被发送,也能够获取服务器端响应的数据,但是请求是在页面加载的过程中被发送的,即请求是在访问html页面的时候被立即发送的,而不是请求在想发送的时候立即发送的(如点击按钮时)。

  1. 客户端需要将函数名称传递到服务器端(服务器返回的函数名称必须和客户端定义的函数名称保持一致)
    实例:客户端定义的名字直接通过请求参数的方式传递到服务器端,服务器端接收到该函数的名字后直接返回函数的调用。因此客户端函数名字的修改将不会影响到服务器端
客户端:
<script>function fn2 (data) {console.log('客户端的fn函数被调用了')console.log(data);}
</script>
<!-- 将非同源服务器段的请求地址写在script标签的src属性中 -->
<script src="http://localhost:3001/better?callback=fn2"></script>服务器端:2号服务器端 app.js文件
const express = require('express');
const path = require('path');
const app = express();
// 静态资源访问服务功能
app.use(express.static(path.join(__dirname,'public')));app.get('/brtter', (req,res) => {//接收客户端传递过来的函数名称const fnName = req.query.callback;   // 将函数名称对应的函数调用代码返回给客户端const result = fnName + '({name: "张三"})';res.send(result);
})
// 监听端口
app.listen(3001);
// 控制台提示输出
console.log('服务器启动成功');
  1. 将script请求的发送变成动态请求
    <button id="btn">点我发送请求</button><script>function fn2 (data) {console.log('客户端的fn函数被调用了')console.log(data);}</script><!-- 将非同源服务器段的请求地址写在script标签的src属性中 --><!-- <script src="http://localhost:3001/better?callback=fn2"></script> --><script type="text/javascript">// 获取按钮var btn = document.getElementById('btn');// 为按钮添加点击事件btn.onclick = function () {// 动态创建script标签var script = document.createElement('script');// 为script标签添加设置src属性script.src = 'http://localhost:3001/better?callback=fn2';// 将srcipt标签追加到页面中document.body.appendChild(script);// 为script标签添加onload事件script.onload = function () {// 将body中的script标签删除掉document.body.removeChild(script);}}</script>
  1. 封装jsonp函数,方便请求发送。(代码重复多次使用,封装以后当想要使用jsonp方式向非同源服务器端发送请求时,只需要调用该函数即可)—和封装ajax函数思路一样
    基础地封装JONSP函数用于发送请求:
    <button id="btn">点我发送请求</button><script>function fn2 (data) {console.log('客户端的fn函数被调用了');console.log(data);}</script>
<script type="text/javascript">// 获取按钮var btn = document.getElementById('btn');// 为按钮添加点击事件btn.onclick = function () {jsonp({   //当前对象为jsonp属性的实参,而在函数定义的时候有一个形参与之对应---options// 请求地址url: 'http://localhost:3001/better?callback=fn2'})}// 当想向非同源服务器发送请求时只需要调用jsonp函数即可function jsonp (options) {// 动态创建script标签var script = document.createElement('script');// 为script标签添加src属性   只有在发送请求,调用jsonp函数的时才会知道请求会发送到哪里去script.src = options.url;// 将script标签追加到页面中,这样请求才能发送出去document.body.appendChild(script);// 为script标签添加onload事件script.onload = function () {document.body.removeChild(script);}}</script>

虽然已经封装jsonp函数用于发送请求,但在函数外部的其他地方还需要另外定义一个函数用于接收服务器端的返回数据:

    <button id="btn">点我发送请求</button><script>function fn2 (data) {console.log('客户端的fn函数被调用了');console.log(data);}</script>
<script type="text/javascript">// 获取按钮var btn = document.getElementById('btn');// 为按钮添加点击事件btn.onclick = function () {jsonp({   //当前对象为jsonp属性的实参,而在函数定义的时候有一个形参与之对应---options// 请求地址url: 'http://localhost:3001/better',success: function (data) {console.log(777);console.log(data);}})}// 当想向非同源服务器发送请求时只需要调用jsonp函数即可function jsonp (options) {// 动态创建script标签var script = document.createElement('script');// rendom()产生0-9之间的随机小数-->需要去掉小数点     函数名:myJsonp0898789var fnName = 'myJsonp' + Math.rendom().toString().replace('.','')// 它已经不是一个全局函数,服务器在返回函数调用时找不到该函数// 因此要想办法将其变成一个全局函数(在JS中window代表全局)window[fnName] = options.success;   //函数名字不能固定,否则连续发送请求时会覆盖掉// 为script标签添加src属性   只有在发送请求,调用jsonp函数的时才会知道请求会发送到哪里去script.src = options.url + '?callback=' + fnName;// 将script标签追加到页面中,这样请求才能发送出去document.body.appendChild(script);// 为script标签添加onload事件script.onload = function () {document.body.removeChild(script);}}</script>

完善:在发送请求时目前只是传递了一个callback参数,若该请求要求传递更多参数时,则就和ajax函数一样,在调用jsonp函数的时候传递一个data属性,属性的值为一个对象,对象中存储的就是想要向服务器端发送的请求参数,在jsonp函数内部,要讲对象转换为‘参数名称=参数值’,多个参数之间用‘&’隔开的字符串

    // 获取按钮var btn = document.getElementById('btn');// 为按钮添加点击事件btn.onclick = function () {jsonp({   //当前对象为jsonp属性的实参,而在函数定义的时候有一个形参与之对应---options// 请求地址url: 'http://localhost:3001/better',data: {name: '王五',age: 17},success: function (data) {console.log(777);console.log(data);}})}// 当想向非同源服务器发送请求时只需要调用jsonp函数即可function jsonp (options) {// 动态创建script标签var script = document.createElement('script');// 拼接字符串的变量var params = '';for (var attr in options.data) {params += '&' + attr + '=' + options.data[attr];}// rendom()产生0-9之间的随机小数-->需要去掉小数点     函数名:myJsonp0898789var fnName = 'myJsonp' + Math.rendom().toString().replace('.','')// 它已经不是一个全局函数,服务器在返回函数调用时找不到该函数// 因此要想办法将其变成一个全局函数(在JS中window代表全局)window[fnName] = options.success;   //函数名字不能固定,否则连续发送请求时会覆盖掉// 为script标签添加src属性   只有在发送请求,调用jsonp函数的时才会知道请求会发送到哪里去script.src = options.url + '?callback=' + fnName + params;// 将script标签追加到页面中,这样请求才能发送出去document.body.appendChild(script);// 为script标签添加onload事件script.onload = function () {document.body.removeChild(script);}}

CORS

CORS 是一个 W3C 标准,全称是"跨域资源共享"(Cross-origin resource sharing)它允许浏览器向跨源服务器,发出 XMLHttpRequest 请求,从而克服了 ajax 只能同源使用的限制

CORS 需要浏览器和服务器同时支持才可以生效,对于开发者来说,CORS 通信与同源的 ajax 通信没有差别,代码完全一样。浏览器一旦发现 ajax 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。

  • 首先前端先创建一个 index.html 页面:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>CORS</title>
</head>
<body><script>const xhr = new XMLHttpRequest();xhr.open('GET', 'http://127.0.0.1:3000', true);xhr.onreadystatechange = function() {if(xhr.readyState === 4 && xhr.status === 200) {alert(xhr.responseText);}}xhr.send(null);</script>
</body>
</html>
  • 这似乎跟一次正常的异步 ajax 请求没有什么区别,关键是在服务端收到请求后的处理:
require('http').createServer((req, res) => {res.writeHead(200, {'Access-Control-Allow-Origin': 'http://localhost:8080'});res.end('这是你要的数据:1234567');}).listen(3000, '127.0.0.1');console.log('启动服务,监听 127.0.0.1:3000');
  • 关键是在于设置相应头中的 Access-Control-Allow-Origin,该值要与请求头中 Origin 一致才能生效,否则将跨域失败。
  • 成功的关键在于 Access-Control-Allow-Origin 是否包含请求页面的域名,如果不包含的话,浏览器将认为这是一次失败的异步请求,将会调用 xhr.onerror 中的函数。

CORS 的优点

  • 使用简单方便,更为安全
  • 支持 POST 请求方式

CORS的缺点

  • CORS 是一种新型的跨域问题的解决方案,存在兼容问题,仅支持 IE 10 以上

Node.js -- 同源和跨域相关推荐

  1. Node.js设置CORS跨域请求中多域名白名单的方法

    允许跨域请求,主要就是配置Response响应头中的 Access-Control-Allow-Origin 属性为你允许该接口访问的域名. 最常见的设置是: res.header('Access-C ...

  2. Vue.js跨域请求配置、Node.js设置允许跨域

    Vue跨域配置 在Vue项目目录中打开config/index.js,在proxyTable中添写如下代码: // 跨域处理proxyTable: {'/api': { // 匹配所有以 '/api' ...

  3. Django基础---Form和modelform校验器、同源和跨域问题

    文章目录 Form和modelform Form自动生成登录标签并校验 其他属性 校验器组件 Hook钩子方法 局部钩子和全局钩子 modelform 同源和跨域 简单请求跨域 Form和modelf ...

  4. js解决iframe跨域问题

    js解决iframe跨域问题 参考文章: (1)js解决iframe跨域问题 (2)https://www.cnblogs.com/qinxuhui/p/12154995.html 备忘一下.

  5. [转] js前端解决跨域问题的8种方案(最新最全)

    [转] js前端解决跨域问题的8种方案(最新最全) 参考文章: (1)[转] js前端解决跨域问题的8种方案(最新最全) (2)https://www.cnblogs.com/chris-oil/p/ ...

  6. 【JS】AJAX跨域-JSONP解决方案(一)

    [JS]AJAX跨域-JSONP解决方案(一) 参考文章: (1)[JS]AJAX跨域-JSONP解决方案(一) (2)https://www.cnblogs.com/h--d/p/11470534. ...

  7. JS中的跨域问题及解决办法汇总

    一.什么是跨域? 在了解跨域之前,首先要知道什么是同源策略(same-origin policy).简单来讲同源策略就是浏览器为了保证用户信息的安全,防止恶意的网站窃取数据,禁止不同域之间的JS进行交 ...

  8. node --- 实践中理解跨域

    经常可以见到.说解决跨域只要返回加上"Access-Control-Allow-Origin"头部就行- 下面从实践中一步一步的理解. 1.环境准备: 1. node.js (ht ...

  9. js中各种跨域问题实战小结

    什么是跨域?为什么要实现跨域呢? 这是因为JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象.也就是说只能访问同一个域中的资源.我觉得这就有必要了解下javascript中的同源策略 ...

最新文章

  1. 李飞飞、邓中翰当选美国国家工程院院士
  2. python调用动态链接库windows_用win从python ctypes调用标准windows.dll的Segfault
  3. Forrester 最新报告:阿里云稳居领导者地位,引领云原生开发浪潮
  4. VTK修炼之道2_VTK体系结构1
  5. 卧槽!Python学习神器~
  6. 连环卡通漫画《转学第一天》
  7. Linux运维-day3
  8. Ubuntu 16.04 安装第三方Apps Can’t Install Third-Party Apps on Ubuntu 16.04? You’re No
  9. 在相册查看保存的图片
  10. oracle12c官方文档中文版_三分钟让你真正读懂oracle12c 中cdb pdb概念及原理
  11. 解决PlayerSettings中的splash Image资源发现在内存中卸载不掉
  12. java工程师的素质模型,优秀程序员必备的四项能力
  13. 蓝桥杯 c语言入门试题,蓝桥杯c语言试题2015
  14. 威纶触摸屏如何设置数值输入元件的上下限和用户密码登录?
  15. layui使用treeTable实现树形表格
  16. 野火指南者移植hal+rtthread+lvgl
  17. 本机修改虚拟机linux中的代码文件
  18. 生吃素食健康驻颜5大注意
  19. 图像特征提取(形状特征,空间关系特征)
  20. PTX JIT compilation failed相关问题

热门文章

  1. 微信小程序 实现底部导航栏tabbar
  2. java实现购物车的原理及步骤_购物车的原理及实现
  3. TreeSelect 回显
  4. python3字典详解_Python3中Dictionary(字典)操作详解
  5. 数组求和的几种实现方法
  6. Flink中window 窗口和时间以及watermark水印
  7. 【树莓派】使用树莓派4B搭建简单的局域网Nas
  8. 【编程100%】22-02 基础算法之KTV
  9. 往Oracle数据库中插入NCLOB/CLOB类型数据
  10. 数据库SQL2017打开 服务报错 请求失败或服务未及时响应