什么是跨域

  • 由于浏览器的同源策略限制,当一个请求 url协议、域名、端口三者之间任意一个与当前页面 url 不同时,需要跨域才能成功访问;

  • 同源策略是浏览器的行为,是浏览器最核心也最基本的安全功能

前端解决跨域方法

其实跨域问题都是找后端解决的;

误区:前端通过 jsonp 解决跨域

原生写法

js
1
2
3
4
5
6
7
8
9
10
1.创建一个script标签
var os=document.createElement("script")
2.给script一个src,src就是地址
os.src="http://suggestion.baidu.com/su?cb=qwer&wd=123"
3.将script插入到页面
document.body.appendChild(os)
4.回调函数处理数据
function qwer(d){
//d就是后端返回的数据
}

ajax 请求

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$.ajax({
url:"http://suggestion.baidu.com/su?",
type:"get",
dataType:"jsonp",
data:{
wd:"123"
},
jsonp:"cb",// 回调参数key
jsonpCallback:"test",// 回调函数value
success:function(res){
console.log(res)
},
error:function(){
console.log("error")
}
})

jsonp

jsonp 实现原理

  • 动态生成 script 标签,通过 src 属性来加载;

  • 默认使用 Jsonp 进行跨域时,请求的 url 地址后面会自动带上一个 callback=xxx 传给后端,后端需要对返回给前端的 json 数据做处理,此处的 callback 可通过 jsonp 来自定义,xxx 可通过 jsonpCallback 来自定义;

  • jsonp: 回调函数的参数,是与后端约定好的参数,必须与后端保持一致。不另外定义 jsonp 的话,一般默认为 jsonp:'callback'

  • jsonpCallback: 回调函数名,用来包裹住 json 数据,不另外定义的话,这个参数的值往往是随机生成的。

  • 按照上面百度搜索的 jsonp 来举例子:http://suggestion.baidu.com/su?cb=test;其中 ?cb=test 中的 cbkeytestvalue

  • 前端会传递一个 callback 参数(key)给后端,接着后端返回数据时会将这个 callback 参数的值(value)作为函数名来包裹住 json 数据,最终返给前端的就是一段 js 代码了;

  • 客户端需要将函数名称传递到服务器 可以如下实现:

js
1
2
3
4
5
6
7
8
//前端
<script>
function fn(data) {
console.log("客户端的函数调用了")
console.log(data)
}
</script>
<script src="http://localhost:3000/test?callback=fn"></script>
js
1
2
3
4
5
6
7
//后端
//路由配置
app.get("/test",(req,res)=>{
var fnName = req.query.callback;
var result = fnName + '({name:"zhangsan"})';
res.send(result);
})

结论

  1. jsonp 方法的实现是需要前端和后端配合的;
  2. jsonp 只支持 get 请求,不支持 post 请求;
  3. jsonp 有安全性问题:jsonp 劫持,jsonp 劫持属于 CSRF 漏洞;

前端通过代理解决跨域

反向代理有很多,可以用 nodejs,可以用 nginx,这里只介绍 nginx

nginx 反向代理

由于同源策略是浏览器导致的;所以可以找一个中间代理服务器;使用这个中间代理服务器去请求后端的地址;因为服务和服务之间是不存在同源策略的,所以中间代理服务器可以请求到后端接口数据;最后前端请求中间代理服务器;

js
1
2
3
4
//常用命令
start nginx 开启
nginx -s stop 停止
nginx -s reload 重新加载
  1. 官网下载稳定版
html
1
http://nginx.org/en/download.html

nginx

  1. 在根目录下,输入 cmd 打开终端

nginx

  1. 在终端中使用指令 start nginx 开启 nginx
  2. 在浏览器输入 localhost,出现如下界面即代表开启成功

nginx

  1. 配置 nginx :nginx.conf 里面配置

后端的 ip + 后端口 之后 最后必须有 /,而且最后的最后必须要带上 ;

nginx

如果不带 ; nginx 命令会不生效;

nginx

如果不带 / ;接口地址为 404;

nginx

  1. 修改前端的请求接口

nginx

  1. 将前端文件放到 nginx文件的html目录下 (也可以不放,见下文的补充)

nginx

  1. 重新加载一下 nginx -s reload,然后在浏览器输入 localhost/myDemo.html

nginx

未经过反向代理的接口为:

nginx

补充

上面第 7 步中,也可以不将前端文件放到 nginx文件的html目录下

  1. 项目通过 vsCode 插件 Live Server 起一个本地服务,地址是 127.0.0.1:5500然后这个服务就不能关掉了,当然页面可以关;

nginx

  1. 修改 nginx 的配置文件

nginx

  1. 重新加载一下 nginx -s reload,然后在浏览器输入 localhost/myDemo.html

nginx

参考文献

关于 Jsonp 跨域,你知道多少?

jsonp 解决跨域问题(简单易懂)

jsonp 劫持

前端解决跨域,nginx 反向代理

正确的 Nginx 跨域配置

前端本地开发如何靠自己解决跨域