0
点赞
收藏
分享

微信扫一扫

JAVA基本运算符和条件控制语句------JAVA入门基础教程

Just_Esme 2023-04-28 阅读 41

好久没有更新博客了,前段时间在疯狂面试,最近工作了才有时间来写博客。
准备来讲讲面试里常问到的跨域处理吧。
说到跨域,我们可能会下意思的说出jsonp,服务端配置cors,node配置代理等,再多了,我可能想不起来了。本篇本来打算只记录postMessage这种方式的,但光说这个显得太单薄了,所以一并都总结一下吧。

跨域是什么,为什么会跨域?
要想知道为什么,你得先知道什么是同源策略。同源策略是浏览器的一个安全协议,它限制了只有在同源的情况下才可以安全访问请求到数据,同源即同一个协议、域名、端口即是同源,比如:

http://localhost:8000

这里http就是协议
localhost是域名
而8000就是端口
协议域名端口哪怕有一个不同,都会造成跨域导致无法正常去请求(否则都乱套了,大家都能随意访问对方的数据,都在裸奔,也就没有隐私而言了)。但我们在日常开发的时候,早已经前后端分离了,所以在联调接口的时候,就会有各种跨域问题。

JSONP

在那个用jq刀耕火种的那个年代,jq就基于xmlHttprequest封装了ajax请求库,在请求配置项里可以直接配置jsonp:true来做跨域请求。原理是利用script标签加载不受跨域的影响,将请求放到script标签的src属性上。同时声明一个回调函数用于接收数据,在请求后面加上这个回调函数,服务端接收到请求后把参数放到回调函数里,本次http连接结束后会自动执行这个回调函数。通过这种方式,我们实现了跨域请求。
上才艺

function jsonp(src) {
	const script = document.createElement("script");
	script.src = `${src}?callback=onSuccess`;
	document.head.appendChild(script);
	script.onload = () => {
		// 加载成功后自动删除该标签
		document.head.removeChild(script)
	}
}

同时声明一个onSuccess函数用于响应请求接收结果

function onSuccess(res) {
	console.log(res);
}

以上:我们声明了一个jsonp函数用于跨域请求数据,并声明一个onSuccess函数用于接收请求数据;
服务端响应(这里以node为例)
随便拉个脚手架搭个node服务,创建一个路由用于测试jsonp跨域请求。

search.get('/test', async ctx => {
  const cb = ctx.query.callback;
  const result = {
    code: 0,
    data: {
      name: 'xxxxxx',
      token: 'xxxxxxxxxxxxxxx'
    }
  }
  ctx.body = `${cb}(${JSON.stringify(result)})`
})

获取请求里的callback参数,把结果放到这个callback方法里;
前端触发jsonp这个方法去请求/search/test 看看结果
在这里插入图片描述
可以看到已经可以成功请求到数据了。至此,通过jsonp方法来跨域我们已经了解了。但是一定要知道这种方式的弊端,为何我们现在都不用Jsonp来做跨域请求了呢?
jsonp它只支持get请求,因为浏览器加载script脚本是通过get方式来请求的,所以没法用post请求了。众所周知的是get和post的区别里 有一条特别重要的是get会直接把请求参数拼接到连接上,相对post来说这是不够安全的。

CORS

服务端通过配置请求头,允许所有的跨域请求;
这里还是以node服务为例,比如Koa库,我们建一个中间件用于处理跨域请求;

app.use(async (ctx, next)=> {
  ctx.set('Access-Control-Allow-Origin', '*');
  ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
  ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
  if (ctx.method == 'OPTIONS') {
    ctx.body = 200; 
  } else {
    await next();
  }
});

在koa实例里use这个middleware
这里主要是配置了Access-Control-Allow-Origin 允许了所有请求都能访问;
关于Access-Control-Allow-Origin的解释看mdn

node代理

现代化前端工程,基本都是通过node来打包构建的。常见的如webpack,vite等,在解决跨域请求的时候,都提供了相关的配置来处理跨域问题。通过配置proxy代理,将请求转发到当前项目里进行请求。
原理是跨域只存在于浏览器端,也就是说只受浏览器的影响,而通过node层去请求则不会有跨域问题。所以在项目开发阶段,把跨域请求转发到当前项目的node层里去请求,就不会有跨域的问题。

禁用同源策略

既然你浏览器有相关的安全协议禁止跨域请求,那我也可以禁用你这个协议,这样我就无视跨域的影响能正常发出请求了。
找到chrome浏览器新建一个快捷方式,点击快捷方式右键属性,找到目标 在目标里加上 --allow-file-access-from-files --user-data-dir="C:\MyChromeUserData" --disable-web-security 点击应用并关闭窗口
在这里插入图片描述
c盘根目录新建一个名叫MyChromeUserData的文件夹用于存储新建的这个浏览器快捷方式的信息
双击桌面上chrome新建的那个快捷方式,如果出现这样的提示,就说明成功了。
在这里插入图片描述

postMessage

页面跨域通信还可以通过postMessage来实现。这个场景是比如通过window.open打开一个小窗口或者页面加载一个iframe,两者需要进行通信。但受跨域影响,两者是无法进行通信的,此时可以通过postMessage来实现通信。
上才艺

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<iframe src="http://localhost:3000/" id="iframe"></iframe>
		<script type="module">
			window.addEventListener('message', (e) => {
				console.log(e.data);
			});
		</script>
	</body>
</html>

页面的地址是http://127.0.0.1:8848/private/index.html,它加载了一个iframe 同时window监听了message并输出结果
http://localhost:3000页面有一个button,给这个btn添加一个点击事件,postMessage方法第一个参数是传输的数据,第二个是传输的页面

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>postmsg</title>
	</head>
	<body>
		<button id="btn">notify parent</button>
		<script>
			document.getElementById("btn").addEventListener("click", () => {
				parent.postMessage('this is postmessage', 'http://127.0.0.1:8848/private/index.html');
			})
		</script>
	</body>
</html>

通过点击btn触发请求,输出e.data,data即是'this is postmessage'


其他的譬如通过Nginx反向代理来实现跨域请求等,这些可以自行去百度了。

举报

相关推荐

0 条评论