前端跨域通信的几种方式

前言

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

  • 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,一经查实,立即删除!

相关文章

T4((Text Template Transformation Toolkit))模版引擎之基础入门 C#中文本模板(.tt)的应用...

1 关于C#中文本模板(.tt)的简单应用https://blog.csdn.net/zunguitiancheng/article/details/78011145 任何一个傻瓜都能写出计算机能理解的程序&#xff0c;而优秀的程序员却能写出别人能读得懂的程序。—— Martin Fowler 2 T4模版引擎之生成数据库实体类 http://www.cnblogs…

LeetCode412Fizz Buzz

写一个程序&#xff0c;输出从 1 到 n 数字的字符串表示。 1. 如果 n 是3的倍数&#xff0c;输出“Fizz”&#xff1b; 2. 如果 n 是5的倍数&#xff0c;输出“Buzz”&#xff1b; 3.如果 n 同时是3和5的倍数&#xff0c;输出 “FizzBuzz”。 示例&#xff1a; n 15, 返回: [ …

vue+node实现中间层同步调用接口

为了应对业务的复杂性&#xff0c;提高前端的渲染能力&#xff0c;故在项目中引入nodejs做中间层&#xff0c;前端承接vue&#xff0c;后端对接Java。 至于为什么这么搞&#xff0c;网上有好多文章都在讨论&#xff0c;可以说仁者见仁智者见智&#xff0c;这里我们不在深究。 …

ES6学习笔记(二十二)ArrayBuffer

ArrayBuffer ArrayBuffer对象、TypedArray视图和DataView视图是 JavaScript 操作二进制数据的一个接口。它们都是以数组的语法处理二进制数据&#xff0c;所以统称为二进制数组。 二进制数组由三类对象组成。 &#xff08;1&#xff09;ArrayBuffer对象&#xff1a; 代表内存之…

如何正确地使用Java的@deprecated标注

没有什么事情比看到一个没有任何说明的deprecated标注更让人愤怒的事情了。这种做法只能让人困惑&#xff0c;我到底还要不要用这个已经‘废弃’的方法&#xff1f;如果开发者不希望某个方法再被人用的话&#xff0c;就要好好地为deprecated标注写说明。这篇文章就讨论了正确地…

实现div里的img图片水平垂直居中

body结构 <body><div><img src"1.jpg" alt"haha"></div> </body>方法一&#xff1a; 将display设置成table-cell&#xff0c;然后水平居中设置text-align为center&#xff0c;垂直居中设置vertical-align为middle。 <…

[ 懒人神器 ] —— OO一键build:.zip - .jar

懒人神器 更新 大家注意一下&#xff0c;由于在写入MANIFEST的时候&#xff0c;Class-Path路径给的是 ../lib &#xff0c;即上级目录的lib。 所以在对拍时如果手动移动了 jar包的位置&#xff0c;需要保证 lib/ 文件夹在存放jar包的上一级目录下&#xff0c;否则在运行时会报错…

实现Datagrid分页

Html页面&#xff1a; <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title></title><meta charset"utf-8" /><!-- 引入相关CSS --><…

Luogu 3698 [CQOI2017]小Q的棋盘

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

h5-plus.webview

这里是链接转载于:https://www.cnblogs.com/yuners/p/10721163.html

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

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

SQL语句01

SQL(Structured Query Language)&#xff1a;结构化查询语言SQL分类&#xff1a; 数据操纵语言DML&#xff08;Data Manipulation Language&#xff09; SELECT INSERT UPDATE DELETE 数据定义语言DDL&#xff08;Data definition language&#xff09; …

mongoose 笔记

快速启动 首先需要安装MongoDB和Node.js。 然后使用npm下载mongoose&#xff1a; npm install mongoose 接着我们直接在项目中引入mongoose&#xff0c;并且连接数据库就会在本地运行 MongoDB了&#xff1a; // index.js var mongoose require(mongoose); mongoose.connect(…

前端DES加密

1、下载crypto.js文件库 https://github.com/brix/crypto-js/releases 2、引入文件 <script type"text/javascript" src"js/jquery.min.js"></script> <script src"js/rollups/tripledes.js"></script> <script src&…

DOMBOM(source、methods、contents、Application)

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

sublime 无法下载插件解决办法(亲测有效)

最近发现sublime装不到插件 只需要在Preferences > Package Settings > Package Control > Settings - User页面加上以下代码即可&#xff1a; "channels":["https://erhan.in/channel_v3.json"]上述频道亲测有效&#xff0c;如果还不能使用的小…

ES命令

基础概念 Elasticsearch有几个核心概念。从一开始理解这些概念会对整个学习过程有莫大的帮助。 接近实时&#xff08;NRT&#xff09; Elasticsearch是一个接近实时的搜索平台。这意味着&#xff0c;从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟&#xff…

Bug : Bash on Ubuntu on Windows scp work on window but not in shell file

&#xff1a; No Permission转载于:https://www.cnblogs.com/rgqancy/p/10726154.html

图片做背景撑开div

需求点&#xff1a; 设计师给了一张超大背景图&#xff0c;需要做一个不知道大小广告位&#xff0c;要求就是要把图片撑满整个页面&#xff0c;而且还得保证自适应。 解决方案一 &#xff08;亲测有效&#xff09; HTML代码&#xff1a; <div class"wrap">…

十一、jQuery的基本用法

初步接触不是很习惯&#xff0c;之前都是用的js&#xff0c;但是jQuery去掉了js很多繁琐的内容&#xff0c;用的不是很熟&#xff0c;所以先简单的记录一下&#xff0c;后续在继续补充 jq获取html内容: $("#id") 获取id $(".class") class名 …