一.同源策略
1.什么是同源策略
同源策略最早由Netscape(网景)公司提出,是浏览器的一种安全策略
2.什么是同源?
同源指的是,协议域名端口号必须完全相同,任何一个不满足条件都会导致跨域问题的产生。
3.什么是跨域?
违背同源策略就是跨域。
4.跨域的解决方案有什么?
- CORS(后端一劳永逸的解决方案)
- JSONP(前端程序员发现的语法糖)
- 代理服务(最常用的跨域解决方案)
二.CORS
1.CROS是什么?
CROS,又叫跨域资源共享。CROS是官方解决跨域的方案,他的特点是不需要在前端(客户端)做任何特殊处理的操作,完全是由后端(服务器)中进行处理,支持GET和POST请求。
2.CROS是怎么工作的?
CROS是由后端设置一个响应头Access-Control-Allow-Origin
来告诉浏览器,请求允许跨域,浏览器收到相应就会放行,很有代表的网站"GetHub",还有一些类似的开源网站,可以允许任何端口来访问本网站的服务器
3.相关响应头介绍:
Access-Control-Allow-Origin
:允许的域名,该字段是必须的,设置为*,表示取消跨域限制Access-Control-Allow-Credentials
:该字段可选,它的值是一个布尔值,表示是否允许发送Cookie,默认情况下Cookie是不会包含在CORS请求之中的。Access-Control-Expose-Headers
:该字段可选,CORS请求时,XMLHttpRequest 对象的 getResponseHeader()方 法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: content-type,cache-control
4.不足之处
- 需要和后端程序员协商,在服务器中取消跨域限制
- 任意的请求协议,域名和端口号都能访问后端的数据接口,这存在着一定的风险。
三.JSONP
1.什么是JSONP?
jsonp是一个非官方的解决跨域的方案
web端调用js文件不受跨域的影响,而且凡是拥有src属性的标签都拥有跨域的能力,如果纯web端解决跨域,就需要远程服务器,将数据装到js文件里。
恰巧我们有一种数据格式是JSON的纯字符数据格式,可以简洁的描述复杂数据,而且JSON还会被js原生支持,所以在客户端可以随心所欲的处理这样的数据。
web端通过调用脚本一样的方式,用来调用跨域服务器上动态生成的JSON文件,这种远程获取数据的形式看起来想ajax,但其实并不一样
为了客户端便于使用,逐渐形成了一种非正式的传输协议JSONP,该协议的一个要点就是允许用户传递一个回调函数的参数给服务端,然后服务器返回数据时,会将这个回调函数的参数作为函数名包裹JSON数据
在HTML中有一些标签天生自带跨域能力,比如:img 、link 、iframe 、srcipt。jsonp就是利用script标签的src属性解决跨域问题
2.使用步骤
// 1.动态创建一个script标签
let script = document.createElement("script");
// 2.设置script的src
srcipt.src = "http://localhost:3000/testAJAX?callback='abc'";
// 3.定义回调函数
function abc(data){
alert(data.name);
}
// 4.将script添加到body中,发送请求
document.body,appendChild(script);
3.不足之处
- JSONP只能支持GET请求,不能支持其他类型的请求
- 它只支持跨域的HTTP请求,不能解决不同域的两个页面之间如何进行js调用的问题。
- 在调用失败的时候,不会返回HTTP的状态码
- 安全性低,如果提供JSONP的服务存在页面注入漏洞,那么他返回的js的内容就会被控制,那么所有调用这个JSONP的网站 都会存在漏洞
四.代理服务器(推荐)
1. Nginx与Node
在工作上,由于工作平台和语言的原因,对于大部分前端开发人员来说,更倾向于用Nodejs来搭建服务器,进而实现一些需求,对Nginx有天然的抗拒感。的确,Nginx中的绝大部分功能,如果单纯的使用Node.js也可以满足和实现。但实际上,Nginx和Node.js并不冲突,都有自己擅长的领域:Nginx更擅长于底层服务器端资源的处理(静态资源处理转发、反向代理,负载均衡等),Node.js更擅长于上层具体业务逻辑的处理。两者可以实现完美组合,助力前端开发。
2. 正反代理
正向代理(客户端代理)
翻墙工具其实就是一个正向代理工具,它会吧访问墙外服务器server的网页请求,代理到一个可以访问该网站的代理服务器proxy上,这个代理服务器proxy把墙外服务器server上的网页内容获取,再转发给客户。
反向代理(服务器代理)
客户端发送的请求,想要访问server服务器上的内容。但将被发送到一个代理服务器proxy,这个代理服务器将把请求代理到和自己属于同一个LAN下的内部服务器上,而用户真正想获得的内容就储存在这些内部服务器上。
这里proxy服务器代理的并不是客户,而是服务器,即向外部客户端提供了一个统一的代理入口,客户端的请求,都先经过这个proxy服务器,至于在内网真正访问哪台服务器内容,由这个proxy去控制。
为什么要Nginx反向代理
使用反向代理最主要的两个原因:
-
(1)安全及权限。
可以看出,使用反向代理后,用户端将无法直接通过请求访问真正的内容服务器,而必须首先通过Nginx。可以通过在Nginx层上将危险或者没有权限的请求内容过滤掉,从而保证了服务器的安全。
-
(2)负载均衡。
单个服务器解决不了,我们增加服务器的数量,然后将请求分发到各个服务器上,将原先请求集中到单个服务器上的情况改为请求分发到多个服务器上,将负载分发到不同的服务器,也就是我们所说的负载均衡。
五.前后端分离项目 vue/react中配置代理
vue项目中配置代理
在vue.config.js文件中,我们需要配置:(vue-cli 3.0)
devServer: {
//代理列表
proxy: {
'/api': {
target: 'http://172.31.46.4:8088', //要代理的域名
changeOrigin: true,//允许跨域
pathRewrite: {
'^/api': '' // 这个是定义要访问的路径,名字随便写
}
}
}
}
在config/index.js文件中,我们需配置:(vue-cli 2.0)
dev: {
proxyTable: {
'/api': {
target: 'http://172.31.46.4:8088', //要代理的域名
changeOrigin: true,//允许跨域
pathRewrite: {
'^/api': '' // 这个是定义要访问的路径,名字随便写
}
}
}
}
/api/getUserMsg` 相当于 `http://172.31.46.4:8088/getUserMsg
/api`相当于`http://172.31.46.4:8088
this.$http.get("/api/getUserMsg", {
}
.then(res => {
})
.catch(function(error) {
});
配置多个代理地址
情形:某个项目时,由于是多个后端配合(A写一般任务的接口,B写技术预研的接口),出现了多个端口。因此,前端也需要配置多个代理。
devServer: {
//代理列表
proxy: {
'/mps-ss': {
target:'http://xxxxxx:7890',//线上1
changeOrigin: true,
pathRewrite: {
'^/mps-ss': '/mps-ss'
}
},
'/mps-fileApi': {
target:'http://xxxxx:7777',//线上2
changeOrigin: true,
pathRewrite: {
'^/mps-fileApi': '/mps-fileApi'
}
},
'/mps-video': {
target:'http://xxxxxx:8090',//返回播放地址
changeOrigin: true,
pathRewrite: {
'^/mps-video': '/mps-video'
}
}
}
}
为什么有的pathRewrite
这个对象,内容不同?
因为,后端接口匹配的路由不同。
在react配值(两种)
(1)(在package.json
里配置proxy), 单一代理
- 1,如代理到本地服务器5000端口, “proxy”:“http://localhost:5000”
- 2,本地服务器是由
nodejs
启动的(express)。路由:app.get('/getStudentsMsg',(req,res)=>{})
。所以,在axios
做请求数据时,直接请求:‘http://localhost:3000/getStudentsMsg’。(详情查看app.js
文件中的button点击事件)
(2)(不在 package.json
里配置proxy,而在项目目录src/
下新建setupProxy.js
文件), 多个代理
如果在package.json
文件中配置:(报错:提示只支持string类型,不支持object.)
"proxy":{
"/api": {
"target": "http://172.19.5.35:9536",
"ws": true
},
"/apc": {
"target": "http://179.19.5.35:9536",
"ws": true
}
},
解决方法:
- 安装
http-proxy-middleware
管理包,cnpm http-proxy-middleware --save
(注意,在create-react-app
脚手架已经下载好了依赖。此步骤可以省略) - 在项目目录
src/
下新建setupProxy.js
文件,然后写入如下代码:
//做多个代理的配置文件
const proxy = require('http-proxy-middleware');
module.exports = function (app) {
app.use(
proxy(
'/api', { //遇见 /api前缀的请求,就会触发该代理配置
target: 'http://localhost:5000',
changeOrigin: true, // 控制服务器接收到的请求头host的值
pathRewrite: {
"^/api": "/api"
}
}),
proxy(
'/apc', {
target: 'http://localhost:7000',
changeOrigin: true,
pathRewrite: {
"^/apc": ""
},
}
)
)
};