## 跨域
跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能 `同源`使用的限制。
* 资源跳转: A链接、表单提交
* ```<link>、<script>、<img>、<frame>等dom标签,还有样式中background:url()、@font-face()等文件外链```
* js发起的ajax请求,Fetch请求等
### 同源策略
**同源策略**是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议 + 域名 + 端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
#### 常见的跨域场景
| **URL** | **说明** | **通信** |
| --- | --- | --- |
| http://www.domain.com/a.js <br> http://www.domain.com/b.js| 同一域名,不同文件或路径 | `允许`|
| http://www.domain.com/a.js <br> https://www.domain.com/b.js| 同一域名,不同协议 | `不允许` |
| http://www.domain.com/a.js <br> http://www.domain.com:8080/b.js | 同一域名,不同端口 | `不允许` |
| http://www.domain.com/a.js <br> http://www.domain2.com/b.js | 不同域名,相同协议 |`不允许` |
| http://www.domain.com/a.js <br> http://172.0.0.1/b.js | 域名和其对应的`ip` | `不允许` |
| http://a.domain.com/a.js <br> http://b.domain.com/b.js | 不同子域名,相同主域名 |`不允许` |
#### 跨域的解决方案
1. **JSONP跨域**
**jsonp**的原理通过`<script>`标签src属性,发送带有callback参数的`GET`请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。
```
// 回调函数
function handleEvent(data) {
console.info(data)
}
// 原生js
let script = document.createElement("script");
script.src = "https://www.baidu.com/sugrec?pre=1&p=3&ie=utf-8&json=1&prod=pc&from=pc_web&sugsid=1432,21090,30211&wd=12&csor=2&pwd=1&cb=handleEvent&_=1576509650094";
document.body.insertBefore(script, document.body.firstChild)
// Jquery
$.ajax({
url: 'https://www.baidu.com/sugrec?pre=1&p=3&ie=utf-8&json=1&prod=pc&from=pc_web&sugsid=1432,21090,30211&wd=12&csor=2&pwd=1&cb=handleEvent&_=1576509650094',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleEvent", // 自定义回调函数名
data: {}
})
```
2. **跨域资源共享(CORS)**
跨域资源共享( [CORS](https://developer.mozilla.org/en-US/docs/Glossary/CORS "CORS: CORS (Cross-Origin Resource Sharing) is a system, consisting of transmitting HTTP headers, that determines whether browsers block frontend JavaScript code from accessing responses for cross-origin requests."))机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。
##### **简单请求**
对于简单请求,浏览器会直接发出`CORS`请求,具体的就是在头信息中,增加一个`Origin`字段。
1. 请求方法使用下列方法中的其中一个
* HEAD
* GET
* POST
2. HTTP头信息不超过以下几个字段
* Accept
* Accept-Language
* Content-Language
* Last-Event-ID
* Content-Type(只限于`application/x-www-form-urlencoded` | `multipart/form-data` | `text/plain`三个值)
```
# Reuqest Header
// 本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。
Origin: https://www.cnblogs.com
Host: constid.dingxiang-inc.com
Accept-Language: zh-CN,zh;q=0.9
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/79.0.3945.79Safari/537.36
```
```
# Response Header
// 服务器端指定允许其他域名访问
Access-Control-Allow-Origin: https://www.cnblogs.com
// 是否允许后续请求携带认证信息(cookies),该值只能是true,否则不返回
Access-Control-Allow-Credentials: true
```
##### **非简单请求**
非简单请求是那种对服务器有特殊要求的请求,譬如`put` `delete`方法,或者`Content-Type`字段类型是`application/json`的,非简单请求在正式通信前,会增加一次请求,称为`预检`请求,也就是`options`方法。
##### **预检请求**
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的`XMLHttpRequest`请求,否则就报错。
~~~http
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: magic
Host: api.alice.com
~~~
与简单请求不同的是,option请求多了2个字段:
`Access-Control-Request-Method`:必须字段,用来列出浏览器的CORS请求会用到哪些HTTP方法。
`Access-Control-Request-Headers`:该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。
##### **预检请求的回应**
服务器收到"预检"请求以后,检查了`Origin`、`Access-Control-Request-Method`和`Access-Control-Request-Headers`字段以后,确认允许跨源请求,就可以做出回应。
~~~http
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT,Delete
Access-Control-Allow-Headers: magic
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
~~~
**Access-Control-Allow-Origin**
* `*`:设置`*`是最简单粗暴的,但是服务器出于安全考虑,很少有人这么做,设置为`*`浏览器将不会发送`cookies`,即使你的`XHR`设置了`withCredentials`。(`Cookie`得有域名保存)
* 指定域:后端指定一个固定的域。
* 请求域动态设置:后端维护一个固定的数组```[<域名1>, <域名2>...]```,使用`request origin`头信息与数组做对比,来做请求域的设置。
**Access-Control-Allow-Methods**
表明服务器支持的所有跨域请求的方法。
**Access-Control-Allow-Headers**
表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
**Access-Control-Allow-Credentials**
表示是否允许发送认证信息(Cookie)。
**Access-Control-Max-Age**
指定本次预检请求的有效期,单位为秒,允许缓存。在缓存期间,不用发出另一条预检请求。
3. **nginx代理跨域**
```
server {
listen 80;
server_name www.a.com;
# img、css、js常规许可,这里主要针对的字体文件(eot|otf|ttf|woff|svg)相关
location / {
add_header Access-Control-Allow-Origin *;
}
# 匹配以/apis/开头的请求
location ^~ /apis/ {
proxy_pass http://www.b.com; #反向代理
}
}
```
4. **nodejs中间件代理跨域**
node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发。
**设置vue.config.js** **(只适合在 本地环境 使用)**
```
# devServer.proxy
module.exports = {
devServer:{
host: 'localhost',//target host
port: 8080,
//proxy:{'/api':{}},代理器中设置/api,项目中请求路径为/api的替换为target
proxy:{
'/api':{
target: 'http://192.168.1.30:8085',//代理地址,这里设置的地址会代替axios中设置的baseURL
changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
//ws: true, // proxy websockets
secure: false, // 使用的是http协议则设置为false,https协议则设置为true
//pathRewrite方法重写url
pathRewrite: {
'^/api': '/'
//pathRewrite: {'^/api': '/'} 重写之后url为 http://192.168.1.16:8085/xxxx
//pathRewrite: {'^/api': '/api'} 重写之后url为 http://192.168.1.16:8085/api/xxxx
}
},
'/pay': {
target: 'http://www.pay.com',
ws: true,
secure:false,
changOrigin: true,
}
}
}
}
```
5. **WebSocket协议跨域**
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。原生WebSocket API使用起来不太方便,推荐使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
```
// 前端
<script src="https://cdn.bootcss.com/socket.io/2.3.0/socket.io.js"></script>
// 与服务器端建立连接
const socket = io('http://www.domain2.com:8080')
// 向服务器端发送信息
socket.emit('sentToServer', '你好,服务器!')
// 3. 获取服务端发送过来的信息
socket.on('sendToClient', message => { console.log(message); })
```
```
// 后端
let http = require('http')
let io = require('socket.io')
server.listen('8080');
console.log('Server is running at port 8080')
// 监听socket连接
io.listen(server).on('connection', function(socket) {
// 接收信息
socket.on('sendToServer', function(msg) {
console.log('data from client: ---> ' + msg);
// 往客户端发送信息
io.emit('sendToClient', '你好,客户端!');
})
})
```
6. **postMessage跨域**
7. **document.domain + iframe跨域**
8. **location.hash + iframe跨域**
9. **window.name + iframe跨域**
10. **关闭浏览器的安全模式**
* 找到chrome安装目录下的 `chrome.exe` 运行程序,以此创建快捷方式,建议把此快捷方式放到桌面;
* 在电脑硬盘里创建一个空文件夹,并记录此文件夹的路径;
* 右键 `chrome 快捷方式`,找到 `属性` 栏目并点击;
* 在 `目标` 位置最后添加语句,` --disable-web-security --user-data-dir=空文件夹的路径`;
* 然后双击 `chrome 快捷方式` 你可以快乐的跨域了。
- 版本控制之Git简介
- Git工作流程
- Git工作区、暂存区、版本库
- Git 指令汇总
- Git 忽略文件规则 .gitignore
- pull request
- HTTP简介
- HTTP - Keep-Alive
- HTTP缓存
- XMLHttpRequest
- Fetch
- 跨域
- HTTP 消息头
- TCP/IP
- TCP首部
- IP首部
- IP 协议
- TCP/IP漫画
- 前端开发规范
- 前端开发规范整理
- 前端未来规划
- HTML思维导图
- CSS思维导图
- 布局
- position,float,display的关系和优先级
- line-height、height、font-size
- 移动端适配
- JS 对象
- JS 原型模式 - 创建对象
- JS 预编译
- 探索JS引擎
- ES