前端跨域问题常用解决方案

一、背景

浏览器因为安全问题有跨域限制,不允许跨域请求资源。所谓同源是指域名、协议、端口完全相同,只有同源的地址才可以相互通过ajax的方式请求。
前后端分离开发的模式下,一般我们的前端资源和后端服务资源会分开部署,这样对系统的架构、负载、吞吐等都有好处,而且也便于扩展。这样就会存在一个跨域问题。


二、前端解决跨域方案

1、JSONP

原理

浏览器不允许跨域请求资源,但允许跨域群请求文件。JSONP主要是利用script的src标签链接外部js文件,以函数调用的形式,将要传递的数据作为函数参数进行传递。

优点

适用于所有浏览器,实现简单。

缺点

只能使用get请求,比较局限,现在不怎么使用了。


2、CORS(跨域资源共享)

原理

普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。

实现

浏览器对于cors请求分为两类:简单请求和非简单请求。

1)简单请求

浏览器直接发出cors请求,在头信息中添加origin字段(协议、端口、域名)。
如果origin在服务器指定的源许可范围内,就会返回几个头信息字段:

Access-Control-Allow-Origin: <必选> 表示服务器允许的请求源 *表示所有源
Access-Control-Allow-Credentials: <可选> true表示允许发送cookies 
Access-Control-Expose-Headers: <可选> 调用getResponseHeader()可以获取的其它字段
2)非简单请求

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求。

优点

支持所有的HTTP请求,基本不需要前端配置,是当前的主流跨域解决方案。

缺点

IE7及以下不兼容。

具体内容可查看:阮一峰的网络日志:跨域资源共享CORS详解


3、nodejs中间件代理跨域

原理

浏览器有同源限制,服务器之间没有。通过中间代理服务器进行请求转发。

实现

node的中间件代理,基础代码可以查看我之前写的一篇博客:使用node服务器简单启动本地项目。在这个的基础上加入代理中转Proxy代码,将请求转发至最终的服务器。
更多情况下,我们前端使用vue-cli脚手架搭建项目,那实现起来就更加方便了。因为webpack中就提供了http-proxy-middleware中间件。所以下面我们就主要讲解在vue-cli项目中的操作。
这里我们先用node.js启一个本地服务器接口作为测试:

// server.js

// 引入express中间件
let express = require('express');
let app = express();

// 定义api 发送数据
app.get('/api', (req, res) => {
    res.json({ name: 'hahaha' })
})

app.get('/test', (req, res) => {
    res.json({ name: 'this is a test' })
})

// 监听服务端口
app.listen(8888, () => {
    console.log('web server running at http://localhost:8888');
});

然后控制台运行node server.js。控制台出现web server running at http://localhost:8888,即表示启动成功。浏览器中输入http://localhost:8888/api和http://localhost:8888/test都可查看我们相对应的数据。

接下来回到我们vue-cli构建的项目,由于我们的项目运行在http://localhost:8000下,如果直接向http://localhost:8888/api发送请求的话,会报跨域错误。这个时候就可以使用proxy做中转。

相关代码如下:

// vue.config.js中添加配置
module.exports = {
	// ...
	devServer: {
		proxy: {
			'/api': {
				target: 'http://localhost:8888', // 代理跨域目标地址
				changeOrigin: true, 
				// pathRewrite: { // 可选 地址重写
					// '^/api': ''
				// }
			}
		}
	}
}

// App.vue 使用axios发送请求测试 注意:此处我将axios作为$http挂载在全局了
export default {
	// ...
	async created() {
		let data = await this.$http.get('/api');
		console.log(data);
	}
}

查看控制台:可以看到接口返回data数据正确,我们的请求被成功处理了。
控制台

查看network也是正常的:
network

优点

搭配vue-cli脚手架使用简单方便。

缺点

只能用于开发环境,项目要打包上线到服务器上就无法使用了。因此建议使用nginx反向代理,它俩解决跨域问题的原理基本一致。


4、Nginx反向代理

这里我们先介绍一下正向代理和反向代理的概念:

正向代理:
正向代理就像一个跳板,它代理的客户端,隐藏真实客户端。
用户无法访问外部资源,可以先访问代理服务器,由它去访问目标地址,然后将内容再转给我们。
从网站的角度,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。

反向代理:
对于客户端而言,它就像是原始服务器,客户端不需要进行任何设置。它代理的是服务端,隐藏真实服务端。
比如我想访问 http://www.test.com/readme,但www.test.com上并不存在readme页面,于是他是偷偷从另外一台服务器上取回来,然后作为自己的内容返回用户,但用户并不知情。这里所提到的 www.test.com 这个域名对应的服务器就设置了反向代理功能。

正向代理
反向代理

原理

ngnix反向代理正是通过ngnix配置一个代理服务器,以此来解决跨域问题。

实现

1)本地电脑windows下安装nginx

nginx官网下载安装包

下载解压后文件夹目录如下:
其中html文件夹下就是用来放我们的项目的。
文件夹目录

2)启动nginx

a、安装解压后,cmd进入到解压后的文件夹中(快捷进入法:打开cmd,输入cd空格,然后将文件夹拉入cmd窗口,回车即可;或者在文件夹下运行git bash);
b、运行相关指令
     启动nginx:start nginx
     重载nginx(nginx配置更新后):nginx -s reload
     停止nginx:nginx -s stop或者nginx -s quit

我们打开浏览器输入:localhost:80(默认地址),如何显示welcome to nginx,则表示启动成功。
网页显示

3)将生产文件放在html文件夹下

接着第3点node中间件代理跨域,我们将vue-cli的项目运行npm run build指令生成dist文件夹。
然后将dist文件夹放入nginx的html文件夹中。然后就可以在浏览器中查看项目:
dist项目
控制台可以看到,axios请求无法找到http://localhost:80/api接口地址,产生报错。这个主要是因为我们开发的时候写的是’/api’相对地址,所以在生产环境下自动加上了前缀域名。但实际上,我们如果写成http:localhost:8888/api绝对地址的话,就会报跨域的错误。
跨域错误

4)配置反向代理

nginx文件夹下打开配置文件,文件路径:conf > nginx.conf进行相关配置:

// ...
server {    
  listen       80; // nginx服务器启动后默认监听端口
  server_name  localhost; // nginx服务器名称    
  // 反向代理访问远程后台接口的配置
  location /api {        
    proxy_pass   http://localhost:8888;  // 反向代理地址
  }
}

然后运行nginx -s restart重启nginx,然后刷新localhost/dist网页进行查看。
控制台:
控制台显示
network:
network
代理成功!

优点

堪称最完美的解决跨域的方案吧。当然,ngnix本身还有其它的很多优点,可以看看其它资料介绍。

缺点

缺点大概就是要配置一下吧…


参考资料

真是要加油学习呢~
[1]: 不要再问题跨域问题了
[2]: b站视频:ngnix反向代理和负载均衡教程
[3]: vue中跨域以及部署nginx跨域设置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值