前端跨域通信的几种方式

前言

前端通信类的问题,主要包括以下内容:

  • 1、什么是同源策略及限制

同源策略是一个概念,就一句话。有什么限制,就三句话。能说出来即可。

  • 2、前后端如何通信

如果你不准备,估计也就只能说出ajax。

  • 3、如何创建Ajax

Ajax在前后端通信中经常用到。做业务时,可以借助第三方的库,比如vue框架里的库、jQuery也有封装好的方法。但如果让你用原生的js去实现,该怎么做?

这就是考察你的动手能力,以及框架原理的掌握。如果能写出来,可以体现出你的基本功。

  • 4、跨域通信的几种方式

这部分非常重要。无非就是问你:什么是跨域、跨域有什么限制、跨域有几种方式

下面分别讲解。

同源策略的概念和具体限制

同源策略:限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。(来自MDN官方的解释)

具体解释:

(1)包括三个部分:协议、域名、端口(http协议的默认端口是80)。如果有任何一个部分不同,则不同,那就是跨域了。

(2)限制:这个源的文档没有权利去操作另一个源的文档。这个限制体现在:(要记住)

  • Cookie、LocalStorage和IndexDB无法获取。

  • 无法获取和操作DOM。

  • 不能发送Ajax请求。我们要注意,Ajax只适合同源的通信。

前后端如何通信

主要有以下几种方式:

  • Ajax:不支持跨域。

  • WebSocket:不受同源策略的限制,支持跨域。

  • CORS:不受同源策略的限制,支持跨域。一种新的通信协议标准。可以理解成是:同时支持同源和跨域的Ajax

如何创建Ajax

关于Ajax请求,可以看本人的基础文章:Ajax入门和发送http请求

在回答 Ajax 的问题时,要回答以下几个方面:

  • 1、XMLHttpRequest 的工作原理

  • 2、兼容性处理

XMLHttpRequest只有在高级浏览器中才支持。在回答问题时,这个兼容性问题不要忽略。

  • 3、事件的出发条件

  • 4、事件的触发顺序

XMLHttpRequest有很多触发事件,每个事件是怎么触发的。

发送 Ajax 请求的五个步骤(XMLHttpRequest的工作原理)

(1)创建XMLHttpRequest 对象。

(2)使用open方法设置请求的参数。open(method, url, 是否异步)。

(3)发送请求。

(4)注册事件。 注册onreadystatechange事件,状态改变时就会调用。

如果要在数据完整请求回来的时候才调用,我们需要手动写一些判断的逻辑。

(5)获取返回的数据,更新UI。

发送 get 请求和 post 请求

get请求举例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body>
<h1>Ajax 发送 get 请求</h1>
<input type="button" value="发送get_ajax请求" id='btnAjax'><script type="text/javascript">// 绑定点击事件document.querySelector('#btnAjax').onclick = function () {// 发送ajax 请求 需要 五步// (1)创建异步对象var ajaxObj = new XMLHttpRequest();// (2)设置请求的参数。包括:请求的方法、请求的url。ajaxObj.open('get', '02-ajax.php');// (3)发送请求ajaxObj.send();//(4)注册事件。 onreadystatechange事件,状态改变时就会调用。//如果要在数据完整请求回来的时候才调用,我们需要手动写一些判断的逻辑。ajaxObj.onreadystatechange = function () {// 为了保证 数据 完整返回,我们一般会判断 两个值if (ajaxObj.readyState == 4 && ajaxObj.status == 200) {// 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的// 5.在注册的事件中 获取 返回的 内容 并修改页面的显示console.log('数据返回成功');// 数据是保存在 异步对象的 属性中console.log(ajaxObj.responseText);// 修改页面的显示document.querySelector('h1').innerHTML = ajaxObj.responseText;}}}
</script>
</body>
</html>

post 请求举例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body>
<h1>Ajax 发送 get 请求</h1>
<input type="button" value="发送put_ajax请求" id='btnAjax'>
<script type="text/javascript">// 异步对象var xhr = new XMLHttpRequest();// 设置属性xhr.open('post', '02.post.php');// 如果想要使用post提交数据,必须添加此行xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");// 将数据通过send方法传递xhr.send('name=fox&age=18');// 发送并接受返回值xhr.onreadystatechange = function () {// 这步为判断服务器是否正确响应if (xhr.readyState == 4 && xhr.status == 200) {alert(xhr.responseText);}};
</script>
</body>
</html>

onreadystatechange 事件

注册 onreadystatechange 事件后,每当 readyState 属性改变时,就会调用 onreadystatechange 函数。

readyState:(存有 XMLHttpRequest 的状态。从 0 到 4 发生变化)

  • 0: 请求未初始化

  • 1: 服务器连接已建立

  • 2: 请求已接收

  • 3: 请求处理中

  • 4: 请求已完成,且响应已就绪

事件的触发条件

事件的触发顺序

上图的参考链接:

  • 你真的会使用XMLHttpRequest吗?

实际开发中用的 原生Ajax请求

var util = {};//获取 ajax 请求之后的jsonutil.json = function (options) {var opt = {url: '',type: 'get',data: {},success: function () {},error: function () {},};util.extend(opt, options);if (opt.url) {//IE兼容性处理:浏览器特征检查。检查该浏览器是否存在XMLHttpRequest这个api,没有的话,就用IE的apivar xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP');var data = opt.data,url = opt.url,type = opt.type.toUpperCase();dataArr = [];}for (var key in data) {dataArr.push(key + '=' + data[key]);}if (type === 'GET') {url = url + '?' + dataArr.join('&');xhr.open(type, url.replace(/\?$/g, ''), true);xhr.send();}if (type === 'POST') {xhr.open(type, url, true);// 如果想要使用post提交数据,必须添加此行xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");xhr.send(dataArr.join('&'));}xhr.onload = function () {if (xhr.status === 200 || xhr.status === 304) { //304表示:用缓存即可。206表示获取媒体资源的前面一部分var res;if (opt.success && opt.success instanceof Function) {res = xhr.responseText;if (typeof res === 'string') {res = JSON.parse(res);  //将字符串转成jsonopt.success.call(xhr, res);}}} else {if (opt.error && opt.error instanceof Function) {opt.error.call(xhr, res);}}};}

Ajax 的推荐链接:https://segmentfault.com/a/1190000006669043

跨域通信的几种方式

方式如下:

  • 1、JSONP

  • 2、WebSocket

  • 3、CORS

  • 4、Hash

  • 5、postMessage

上面这五种方式,在面试时,都要说出来。

1、JSONP

面试会问:JSONP的原理是什么?怎么实现的?

在CORS和postMessage以前,我们一直都是通过JSONP来做跨域通信的。

JSONP的原理:通过<script>标签的异步加载来实现的。比如说,实际开发中,我们发现,head标签里,可以通过<script>标签的src,里面放url,加载很多在线的插件。这就是用到了JSONP。

JSONP的实现:

比如说,客户端这样写:

<script src="http://www.smyhvae.com/?data=name&callback=myjsonp"></script>

上面的src中,data=name是get请求的参数,myjsonp是和后台约定好的函数名。
服务器端这样写:

myjsonp({data: {}
})

于是,本地要求创建一个myjsonp 的全局函数,才能将返回的数据执行出来。

实际开发中,前端的JSONP是这样实现的:

<script>var util = {};//定义方法:动态创建 script 标签/*** [function 在页面中注入js脚本]* @param  {[type]} url     [description]* @param  {[type]} charset [description]* @return {[type]}         [description]*/util.createScript = function (url, charset) {var script = document.createElement('script');script.setAttribute('type', 'text/javascript');charset && script.setAttribute('charset', charset);script.setAttribute('src', url);script.async = true;return script;};/*** [function 处理jsonp]* @param  {[type]} url      [description]* @param  {[type]} onsucess [description]* @param  {[type]} onerror  [description]* @param  {[type]} charset  [description]* @return {[type]}          [description]*/util.jsonp = function (url, onsuccess, onerror, charset) {var callbackName = util.getName('tt_player'); //事先约定好的 函数名window[callbackName] = function () {      //根据回调名称注册一个全局的函数if (onsuccess && util.isFunction(onsuccess)) {onsuccess(arguments[0]);}};var script = util.createScript(url + '&callback=' + callbackName, charset);   //动态创建一个script标签script.onload = script.onreadystatechange = function () {   //监听加载成功的事件,获取数据if (!script.readyState || /loaded|complete/.test(script.readyState)) {script.onload = script.onreadystatechange = null;// 移除该script的 DOM 对象if (script.parentNode) {script.parentNode.removeChild(script);}// 删除函数或变量window[callbackName] = null;  //最后不要忘了删除}};script.onerror = function () {if (onerror && util.isFunction(onerror)) {onerror();}};document.getElementsByTagName('head')[0].appendChild(script); //往html中增加这个标签,目的是把请求发送出去};</script>

2、WebSocket

WebSocket的用法如下:

//var ws = new WebSocket('wss://echo.websocket.org'); //创建WebSocket的对象。参数可以是 ws 或 wss,后者表示加密。//把请求发出去ws.onopen = function (evt) {console.log('Connection open ...');ws.send('Hello WebSockets!');};//对方发消息过来时,我接收ws.onmessage = function (evt) {console.log('Received Message: ', evt.data);ws.close();};//关闭连接ws.onclose = function (evt) {console.log('Connection closed.');};

Websocket的推荐链接:http://www.ruanyifeng.com/blog/2017/05/websocket.html

3、CORS

CORS 可以理解成是既可以同步、也可以异步*的Ajax。

fetch 是一个比较新的API,用来实现CORS通信。用法如下:

// url(必选),options(可选)fetch('/some/url/', {method: 'get',}).then(function (response) {  //类似于 ES6中的promise}).catch(function (err) {// 出错了,等价于 then 的第二个参数,但这样更好用更直观});
  • CORS的推荐链接:http://www.ruanyifeng.com/blog/2016/04/cors.html

推荐链接里有详细的配置。

另外,如果面试官问:“CORS为什么支持跨域的通信?”

答案:跨域时,浏览器会拦截Ajax请求,并在http头中加Origin。

4、Hash

url的#后面的内容就叫Hash。Hash的改变,页面不会刷新。这就是用 Hash 做跨域通信的基本原理。

补充:url的?后面的内容叫Search。Search的改变,会导致页面刷新,因此不能做跨域通信。

使用举例:

场景:我的页面 A 通过iframe或frame嵌入了跨域的页面 B。

现在,我这个A页面想给B页面发消息,怎么操作呢?

(1)首先,在我的A页面中:

//伪代码var B = document.getElementsByTagName('iframe');B.src = B.src + '#' + 'jsonString';  //我们可以把JS 对象,通过 JSON.stringify()方法转成 json字符串,发给 B

(2)然后,在B页面中:

 // B中的伪代码window.onhashchange = function () {  //通过onhashchange方法监听,url中的 hash 是否发生变化var data = window.location.hash;};

5、postMessage()方法

H5中新增的postMessage()方法,可以用来做跨域通信。既然是H5中新增的,那就一定要提到。

场景:窗口 A (http:A.com)向跨域的窗口 B (http:B.com)发送信息。步骤如下。

(1)在A窗口中操作如下:向B窗口发送数据:

// 窗口A(http:A.com)向跨域的窗口B(http:B.com)发送信息Bwindow.postMessage('data', 'http://B.com'); //这里强调的是B窗口里的window对象

(2)在B窗口中操作如下:

// 在窗口B中监听 message 事件Awindow.addEventListener('message', function (event) {   //这里强调的是A窗口里的window对象console.log(event.origin);  //获取 :url。这里指:http://A.comconsole.log(event.source);  //获取:A window对象console.log(event.data);    //获取传过来的数据}, false);

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/249154.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Luogu 3698 [CQOI2017]小Q的棋盘

BZOJ 4813 虽然数据范围很迷人&#xff0c;但是想树形$dp$没有前途。 先发现一个事情&#xff0c;就是我们可以先选择一条链&#xff0c;最后要走到这一条链上不回来&#xff0c;走到链上的点每一个只需要一步&#xff0c;而如果要走这条链之外的点&#xff0c;一个点需要走两步…

解决vue打包后静态资源路径错误的问题

vue项目完成的最后一步就是打包部署上线&#xff0c;但是打包部署的过程往往不是那么一帆风顺的&#xff0c;现将遇到问题和解决方案记录如下。 图片路径问题 起因&#xff1a; 页面中引入资源的方式往往有如下几种 * HTML标签中直接引入图片&#xff0c; 如 <img src&qu…

DOMBOM(source、methods、contents、Application)

何为DOM&#xff1f; Document Object Model Dom&#xff0c;是W3C组织推荐的处理可扩展标志语言的标准编程接口。在网页上&#xff0c;组织页面的对象被组织在一个树形结构中&#xff0c;用来表示文档中对象的标准模型就称为DOM。 可以认为DOM是页面上数据和结构的一个树形表示…

spring-注解---IOC(3)

spring--注解---IOC(3) package com.zwj.bean;public class Blue {public Blue(){System.out.println("blue...constructor");}public void init(){System.out.println("blue...init...");}public void detory(){System.out.println("blue...detory..…

在div中设置文字与内部div垂直居中

要实现如图一所示的结果&#xff1a; html代码如下&#xff1a; <!DOCTYPE html> <html><head lang"zh"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta charset"utf-8" /><title>商…

王之泰201771010131《面向对象程序设计(java)》第九周学习总结

第一部分&#xff1a;理论知识学习部分 第7章异常、日志、断言和调试 概念&#xff1a;异常、异常类型、异常声明、异常抛出、 异常捕获1.异常处理技术2.断言的概念及使用3.基本的调试技巧 1&#xff09;异常的概念 a.Java的异常处理机制可以控制程序从错误产生的 位置转移到能…

Java学习——使用Static修饰符

程序功能&#xff1a;通过两个类 StaticDemo、LX4_1 说明静态变量/方法与实例变量/方法的区别。 package Pack1;public class Try {public static void main(String[] args) {// TODO Auto-generated method stubSystem.out.println("静态变量x"StaticDemo.getX());非…

JavaScript从入门到精通之入门篇(一)概念与语法

入门篇大纲 第一部分 概念与语法 1.JavaScript的历史 2.基本概念 3.JavaScript的使用、调试和异常处理 4.基本词法和变量 5.数据类型和类型转换 6.运算符 算数运算符 赋值运算符 一元运算符 使用一元运算符&#xff0c;将会把所有的内容转换为数值运算&#xff0c;不…

【小记】-005--纯CSS实现的小玩意儿

效果图奉上 代码奉上 <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible&q…

JavaScript从入门到精通之入门篇(二)函数和数组

入门篇大纲 第二部分 函数与数组 1.函数 函数的定义 普通函数 function 函数名 &#xff08;表达式1…&#xff09; { 代码块 }js是解释性语言&#xff0c;在当前script标签代码执行的开始阶段&#xff0c;就会将普通函数放入堆中&#xff0c;也只是将引用放入堆中&#xf…

一道Python面试题

无意间&#xff0c;看到这么一道Python面试题&#xff1a;以下代码将输出什么&#xff1f; def testFun(): temp [lambda x : i*x for i in range(4)] return temp for everyLambda in testFun(): print (everyLambda(2))脑中默默一想&#xff0c;这还用说么&#xff0c;肯定是…

Windows下的ssh姐妹花 Xshell 和 Xftp

Windows下的ssh姐妹花 Xshell 和 Xftp 今天是3月8号&#xff0c;中国传统的三八妇女节&#xff0c;是距离中国新兴节日三七女生&#xff08;神&#xff09;节最近的一个全国性节日&#xff0c;今天我也是宅在家&#xff0c;研究了一下近日工作上遇到的一个纯软件技术问题。废话…

关于数字证书理解的简单整理以及12306站点证书简单分析

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 https://blog.csdn.net/sundacheng1989/article/details/25540601 首先简单理解一下什么是数字证书。这里是一篇英文文档&#xff0c;描写叙述的非常形象。形象的描写叙述了什么是公钥。什么是私钥。…

Mac中安装Node和版本控制工具nvm遇到的坑

首先说说常规的安装 1. 下载nvm,使用nvm来管理Node版本 官方文档 windows 版本  https://github.com/coreybutler/nvm-windows mac 版本    https://github.com/creationix/nvm#install-script 命令行 尽量不要用brew&#xff0c;免得掉坑 curl -o- https://raw.githubu…

wepy - 与原生有什么不同(x.wpy)使用实例

源码 1 <template>2 <view classmark wx:if"{{showMark}}">3 <view animation"{{animationData}}" class"animCat">4 <image src"http://osk1hpe2y.bkt.clouddn.com/18-5-30/34559443.jpg"></…

CSS实现div梯形分割

原理 使用的border边框属性结合svg 转换 详见代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>css实现div边框斜角</title><style type"text/css"> .labels {display: i…

算法学习——决策单调性优化DP

update in 2019.1.21 优化了一下文中年代久远的代码 的格式…… 什么是决策单调性&#xff1f; 在满足决策单调性的情况下&#xff0c;通常决策点会形如1111112222224444445555588888..... 即不可能会出现后面点的决策点小于前面点的决策点这种情况。 那么这个性质应该如何使用…

SVG画一个箭头

参考菜鸟手册&#xff1a; https://www.runoob.com/svg/svg-tutorial.html 打开菜鸟中的在线工具 在可视化截图拖拉元素绘制箭头 点击command U 查看源码 将源码拷入html代码中&#xff0c;查看效果 最后&#xff0c;贴出源码供大家参考 <!DOCTYPE html> <…

数字签名与HTTPS详解

因为HTTP协议本身存在着明文传输、不能很好的验证通信方的身份和无法验证报文的完整性等一些安全方面的确点&#xff0c;所以才有了HTTPS的缺陷。HTTPS确切的的说不是一种协议&#xff0c;而是HTTP SSL (TSL)的结合体。HTTP报文经过SSL层加密后交付给TCP层进行传输。SSL(安全套…

WPF效果(GIS三维续篇)

去年这个时候简单的摸索了一下三维的GIS相关的东西,也就是仅仅玩耍了一把,这次来点真正用的上的干货效果效果&#xff1a; 1、加载自定义百度样式的瓦片效果 2、加载自定义百度样式的缩放效果 3、快速手动进去咱的大帝都 4、加载海量Mark效果 5、加载海量Mark和简单模型效果 6、…