什么是跨域
- 当协议 、域名 、 端口中任意一个与当前页面的地址不同的就是跨域
- 最常见的跨域就是一个域名的网页中调用另一个域名的资源
为什么要跨域
为了安全起见
浏览器才用同源策略, 对 js 进行了限制, 防止恶意用户获取非法数据, 防止大部分 XSS 攻击 (用户接口注入 js 脚本)
-
浏览器的两种同源策略 会造成跨域
-
DOM 同源策略: 禁止对不同源页面的 DOM 操作, 主要包括
iframe、canvas之类的, 不同源的iframe禁止数据交互, 含有不同源的canvas会受到污染无法进行操作 -
XmlHttpRequest: 禁止不同源的数据交互, 用来防止 CSRF 攻击
跨域请求浏览器报错
- CROS 标准定义了跨域访问资源时浏览器和服务器怎么通信, 浏览器在发生跨域请求时会附加一些头信息和服务器进行沟通, 来确定请求通不通过 (除 IE10 以下的浏览器都支持这个标准)
-
-
跨域的请求分为两种: 简单请求和非简单请求
简单请求
-
请求方法
- GET
- POST
- HEAD
-
头信息
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type //该字段类型不能是 application/json
-
同时满足这 2 点请求的就是简单请求, 其它的都是非简单请求
-
当浏览器把跨域请求设置为简单请求的时候, 就会在头信息中附加上一个字段 Origin, 该字段就会把这次请求的来源 (协议, 域名, 端口) 带给服务器, 服务器就会检查这个请求的来源
-
如果服务器通通过请求来源, 响应浏览器时会附加几条字段
- Access-Control-Allow-Origin, 服务器同意请求的来源, 如果是 * 就代表所有来源
- Access-Control-Allow-Credentials, 浏览器可以发 Cookie 过来, 得到服务器的认可, 浏览器可以正常收到回应
-
如果服务器不同意请求, 服务器正常返回数据, 不会附加, 浏览器没有 Access-Contril-Allow-Origin 会报错, 状态码各种各样, 甚至可能是 200
非简单请求
-
非简单请求, 如 PUT 或者 DELETE 请求, 还有 Content-Type 为 application/json 的, 浏览器会在跨域请求前, 发送请求方式为 OPTIONS 的预检, 头信息不光有 Origin 字段还有
- Access-Control-Request-Method, 告诉服务器跨域请求的方式
- Access-Contril-Request-Headers, 浏览器跨域请求时要额外附加的信息
-
服务器收到预检的请求信息时, 不仅检查来源, 还要检查请求方式和头信息字段
-
如果服务器同意请求, 会在 HTTP 响应中附加上 Access-Control-Allow-Origin, 写着服务器同意请求的来源, 这就意味着得到服务器的认可, 接下去的每次跨域请求都会正常进行
-
如果服务器不同意请求, 服务器正常响应, 不附加任何东西, 浏览器看不见 Access-Control-Allow-Origin, 不会发送跨域请求并且直接报错
如何解决跨域问题
-
JSONP (淘汰)
- 像 img, script 等标签是没有跨域限制的, 所以可以动态创建 script 标签, 通过 src 属性来进行跨域请求, 存放跨域请求的来源
function (data) {
console.log(data)
}
var body = document.getElementByTagName('body')[0]
var script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'http://example.com?jsonp=cb'
body.appendChild(script)
返回的 js 脚本会直接执行, 兼容所有浏览器, 但是有缺点
a. 只能通过 GET 方式进行请求, 一方面参数长度有限制, 一方面安全性较差
b. 后端需要知道前端的 cb 结构, 需要知道参数和回调函数的名字
c. 后端需要进行参数和回调函数拼接后才能执行
d. 随着 RESTful 兴起, JSONP 已经被淘汰, 因为 RESTful 包含 GET, POST, PUT, PATHC, DELETE
-
服务器代理 CROS(常用)
- CROS 全称 Cross Origin Resource Sharing 跨源共享
- 客户端上 CROS 请求和 AJAX 请求没有区别, 区别在服务器端添加附加信息
Access-Control-Allow-Origin - 服务器没有跨域限制, 可以让服务器去请求跨域资源然后在返回给客户端, 客户端将跨域浏览器传给服务器, 服务器请求到资源后再传给客户端
- 浏览器先以 OPTIONS 发送预请求, 获得服务器端队跨源请求所支持的 HTTP 方法, 在确认服务器允许跨源请求后, 以实际的 HTTP 请求方法发送请求
- CROS 不支持 IE8, IE9
-
搭建中间层 (常用)
- 讲不同源的请求转化为同源请求
- 通过搭建中间层,当然可以是 java,也可以是 node.js,通过将服务端的请求进行转发, 那么前端请求的地, 就被转发了, 所以很好的解决跨域问题
- 因为多了一层中间转发, 不管是网络开销, 还是性能负载都是有一定的影响
-
Nginx 反向代理 (常用)
- 搭建中转 Nginx 服务器转发请求
- Naginx 解析 URL 地址的时候进行判断, 将请求转发到具体的服务器上
nginx.conf加入如下代码:
server
{
listen 8000;
server_name svsapi.svsmarkets.com;
# root /var/www/SFWEBSITE/API/public;
index index.php index.htm index.html;
location ~ \.php$ {
add_header Access-Control-Allow-Origin *; //关键
add_header Access-Control-Allow-Headers Content-Type,access-token,language,Cookie; //关键
add_header Access-Control-Allow-Method GET,POST,OPTIONS; //关键
root /var/www/SFWEBSITE/API/public;
fastcgi_pass 127.0.0.1:9001;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location / {
if (!-f $request_filename){
rewrite ^(.*)$ /index.php?$1 last;
break;
}
}
error_log /usr/local/nginx/logs/error_svsapi_svsmarkets_com_log;
access_log /usr/local/nginx/logs/access_svsapi_svsmarkets_com_log;
}
- vue中前后端分离,前端访问后端接口跨越解决办法:
在项目的根目录下的vue.config.js文件中填写以下代码:
a.如果没有vue.config.js文件,自己创建一个。填入以下代码。
b.如果这里设置了域名,而且用了axios请求后台,axios的baseUrl就不用设置域名了。
c.如果8080端口被其他应用占用,按照在启动项目后的终端窗口的端口配置到这里。
d.文中'/api'是访问后台接口的接口,只有是以'api'的才能代理。如:http://192.168.1.52/api/home/change/park
module.exports = {
devServer: {
host:'localhost',
port: 8081,
proxy: {
'/api': {
target: 'http://192.168.1.52',//要跨域的域名
secure: false, //如果是https接口,如要配置此参数
changeOrigin: true,//允许跨域
}
}
},
lintOnSave: false
}