关于跨域

跨域是什么?

出于浏览器的同源策略限制。

同源策略(Sameoriginpolicy) 是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。

可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port);

当一个请求url的协议域名端口三者之间任意一个与当前页面url不同即为跨域

当前页面url被请求页面url是否跨域原因
http://www.test.com/http://www.test.com/index.html同源(协议、域名、端口号相同)
http://www.test.com/https://www.test.com/index.html跨域协议不同(http/https)
http://www.test.com/http://www.baidu.com/跨域域名不同(test/baidu)
http://www.test.com/http://blog.test.com/跨域域名不同(www/blog)
http://www.test.com:8080/http://www.test.com:7001/跨域端口号不同(8080/7001)

如何解决跨域(原理)

正向代理

这种经常应用于本地生产环境中

vue、react项目的运行需要nodejs环境,用此环境可以做一个代理服务器,也就是中间层

在请求发送(接收)之前加入中间层,将不同的域名转换成相同的,就解决了跨域的问题。客户端发送请求时,不直接到服务器,而是先到代理的中间层,利用中间者去代理

1、浏览器向中间者发送请求
2、中间者把请求给到服务器
3、服务器发送结果给中间者
4、中间者发送结果给浏览器

在这里插入图片描述

比如下面这个例子:

直接请求:两个地址的端口不一样,产生了跨域
在这里插入图片描述

配置代理后请求:

在这里将http://localhost:8080的这个域名装换为http://localhost:8081,
再将请求发送到服务器,这样在服务器端收到的请求就是使用的http://localhost:8081;
同理,当服务器返回数据的时候,也是先到代理的中间层,
将http://localhost:8081转换成http://localhost:8080,这样在客户端也是在同源下访问的了。

在这里插入图片描述

反向代理

此方法常用于服务器端,由客户端向反向代理服务器发送请求,反向代理服务器向真实服务器请求
在这里插入图片描述

反向代理正向代理的区别:

他们的行为是一样的,都是通过代理服务器去转发请求给目标服务器

区别是:正向代理是客户机和代理服务器之间是透明的,反向代理代理服务器和目标服务器是透明的。

反向代理可以做负载均衡。
正向代理可以做cdn缓存,还有我们用的vpn;

正向代理隐藏真实客户端,反向代理隐藏真实服务端。

实现代码

使用建议及常见问题见最下方

开发环境(本地运行项目)

假设接口域名www.fuwuqi.cn

使用

对于不同配置的使用是一样的,建议先看一下下面的常见问题在制作

axios({
	url:'/api/register',	//最终相当于https://www.fuwuqi.cn/api/register
	// 其他配置项不在展示
  ).then(function (res) {
      console.log(res);
})

vue-cli 4之前版本项目

先找到config/index.js,dev对象下的proxyTable中
写法:

proxyTable: {
   '/api': {
     target: "www.fuwuqi.cn/api", // API服务器的地址
     changeOrigin: true, // 如果设置为true,那么本地会虚拟一个服务器接收你的请求并代你发送该请求,这样就不会有跨域问题(只适合开发环境)
     pathRewrite: {
       '^/api': '' // 重写路径,根据需要配置,见上面常见问题的问题1,比如'/api/aaa/ccc'重写为'/aaa/ccc'
     }
   }
 },

重启项目

vue-cli 4之后项目

需要新建vue.config.js 【默认情况下,4以上的版本可以直接识别这个js文件,把它当做自己的配置文件】

步骤如下:

1、在项目框架的根目录下新建文件:vue.config.js

2、给新建的文件内添加解决跨域的代码部分

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'https://域名/api',// API服务器的地址
        ws: true,  //代理websockets
        changeOrigin: true, // 虚拟的站点需要更管origin
        pathRewrite: {   //重写路径 比如'/api/aaa/ccc'重写为'/aaa/ccc'
           '^/api': ''
        }
      }
    }
  }
}

3、重启项目,这样的话新建的文件就可以被识别了,一定要重启

基于vite的项目

新建vite.config.js,如果有直接修改
在defineConfig中添加以下代码

server:{
    proxy:{
      '/api': {
        target: 'http://域名/api',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '')// 重写路径
      }
    }
  }

生产环境

保持前端不动,依旧是代理状态
在项目打包部署后,原来的本地代理就不能生效了,就需要使用NginxApache进行反向代理;

假设:

前端项目域名:www.qian.cn
后端项目域名:www.hou.cn

宝塔面板直接可视化修改

修改方法

1、打开宝塔面板,进入网站配置列表,找到需要配置的网站
2、点击设置—》反向代理
3、添加反向代理,然后就ok了

Apache环境:

Apache不提供内容替换

在这里插入图片描述

Nginx环境:

在这里插入图片描述
本地怎么配置,建议线上怎么进行配置

假设接口的地址是:http://www.hou.com/api/index/index

代理名称:可以随便起,尽量跟代理目录一致
代理目录:打开高级功能会显示,就是域名后面的/api
目标URL:http://www.hou.com/api
发送域名:会自动生成
内容替换:跟本地的一样,用于替换

如有问题,见上面的常见问题

修改Apache

Apache不提供内容替换

1. 修改Apache安装目录下的/conf/httpd.conf;如果是宝塔面板直接这里修改:

宝塔面板目录:根目录/www/server/apache/conf/httpd.conf;
本地小皮面板:安装目录\Extensions\Apache2.4.39\conf\httpd.conf;
在这里插入图片描述

2. 分别找到这两行,把前面的注释(#)去掉,启用代理
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
3. 找到/www/server/panel/vhost/apache目录下的www.qian.cn.conf

宝塔面板目录:根目录/www/server/panel/vhost/apache;
本地小皮面板:安装目录\Extensions\Apache2.4.39\conf\vhosts;

添加如下代码:

#PROXY-START/api
<IfModule mod_proxy.c>
    ProxyRequests on
    SSLProxyEngine on
    ProxyPass /api https://www.hou.com/api
    ProxyPassReverse /api https://www.hou.com/api
</IfModule>
#PROXY-END/api
4. 保存并重启Apache

修改Nginx配置

1. 修改Nginx安装目录下的/conf/nginx.conf;如果是宝塔面板直接这里修改:

宝塔面板目录:根目录/www/server/nginx/conf;
本地小皮面板:安装目录\Extensions\Nginx1.15.11\conf;
在这里插入图片描述

2. 找到/www/server/panel/vhost/nginx目录下的www.qian.cn.conf

宝塔面板目录:根目录/www/server/panel/vhost/nginx;
本地小皮面板:安装目录\Extensions\Nginx1.15.11\conf\vhosts;
添加如下代码

# 代理名称
location /api
{
	# 目标url
    proxy_pass https://www.hou.com;
	# 发送域名
    proxy_set_header Host www.hou.red;
	#内容替换
	sub_filter "/api" "";
}
3. 保存并重启Nginx

配置建议

一下几种场景

1、项目只有一个接口地址

按照上面的进行配置即可

2、项目有多个接口地址,地址的域名不一样,但接口都是api模块

本地开发环境配置:

		proxy:{
            '/api':{
                target:'https://域名1/api',
                pathRewrite: {
                    '^/api': ''
                 }
            },
            '/pcapi':{ // 不要起api2,不然还是会被前面的api识别
                target:'http://域名2/api',
                pathRewrite: {
                    '^/pcapi': ''
                 }
            }
        }

使用:

	created(){
        axios({
            url:"/api/index/index"
        }).then((res)=>{
            console.log(res);
        })
        axios({
            url:"/pcapi/index/index"
        }).then((res)=>{
            console.log(res);
        })
    },

服务器配置代理:

其他配置参考上面
# 代理名称
location /api
{
	# 目标url
    proxy_pass https://域名1/api;
	# 发送域名
    proxy_set_header Host travel.qhynice.top;
	#内容替换
	sub_filter "/api" "";
}
# 代理名称
location /pcapi
{
	# 目标url
    proxy_pass http://域名2/api;
	# 发送域名
    proxy_set_header Host wxmall.kuxia.top;
	#内容替换
	sub_filter "/pcapi" "";
}

3、项目有多个接口地址,域名相同但模块不同

比如接口地址:
https://www.fuwuqi.cn/api/index/index
https://www.fuwuqi.cn/pcapi/index/index
本地开发环境配置:

		proxy:{
            '/api':{
                target:'https://域名/api',
                pathRewrite: {
                    '^/api': ''
                 }
            },
            '/pcapi':{ 
                target:'http://域名/pcapi',
                pathRewrite: {
                    '^/pcapi': ''
                 }
            }
        }

使用:

	created(){
        axios({
            url:"/api/index/index"
        }).then((res)=>{
            console.log(res);
        })
        axios({
            url:"/pcapi/index/index"
        }).then((res)=>{
            console.log(res);
        })
    },

服务器分享代理:

其他配置参考上面
# 代理名称
location /api
{
	# 目标url
    proxy_pass https://域名/api;
	# 发送域名
    proxy_set_header Host travel.qhynice.top;
	#内容替换
	sub_filter "/api" "";
}
# 代理名称
location /pcapi
{
	# 目标url
    proxy_pass http://域名/pcapi;
	# 发送域名
    proxy_set_header Host wxmall.kuxia.top;
	#内容替换
	sub_filter "/pcapi" "";
}

一些常见问题

后面的配置以后如果出现问题,先看看这里有没有一些常见的错误

1、要不要配置重写路径

取决于你的路径中需不需要,比如:
1、配置文件中写的是https://www.fuwuqi.cn/api,使用接口处写的是/api/register,这样拼接的是https://www.fuwuqi.cn/api/api/register,多了一个/api,这样就需要重写路径,把其中一的替换成空字符串
2、配置文件中写的是https://www.fuwuqi.cn,使用接口处写的是/api/register,这样拼接的是https://www.fuwuqi.cn/api/register,地址正好,就不需要了
3、如果两个不同域名地址的接口都是/api,那配置的时候其中一个就要配置成/api2,但地址上是/api,这就需要用到它,将/api2替换成/api,保证地址的正确性

总结一句话:自己去拼接一下,看看最后得到的返回对不对

2、配置后接口报错404

一般情况下是地址配置错了,从以下几个方面去找:
1、先确定接口有没有问题,用postman等进行测试
2、检查你的地址有没有写错,像配置那里的域名,使用那里的地址
3、检查你的配置项,看看是不是路径重写那里配置错了,见上面的问题1

3、上面两点都没问题,代理还是不生效

重启项目!!!
让配置项加载进去

4、出现请登录等提示

以thinkPHP为例,接口地址是:https://www.fuwuqi.cn/api/index/index
这中间的api是指的api模块
thinkPHP中地址访问是需要添加后面的模块地址的,否则直接访问域名就是admin模块,而admin一般是后台管理的,需要进行登录,所以你才会见到返回请登录

解决方法:1、配置处不直接写域名,改为域名/api,比如https://www.fuwuqi.cn/api
2、将重写路径打开,让它见多的/api替换掉
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐