1. 什么是跨域
不同源之间的数据访问称之为跨域
当跨域访问数据时, 如果没有特地做过处理, 则无法获取不同源的数据(通过标签引用 js
, img
, css
是可以的, 因为虽然我们通过标签获取到了这些资源, 但是我们仍然不知道对应文件中的内容是什么)
1.1 什么是源
所谓的源是指 协议+域名+端口号
如果两个 url
之间的 协议, 域名, 端口号 中有任意一个不同, 则称这两个 url
不同源(即使是两个不同的域名指向同一个 IP 地址也一样是不同源的)
1.2 为什么会有同源策略
1995年, 同源策略由 Netscape 公司引入浏览器. 最初, 它的含义是指: A网页设置的 Cookie
, B网页不能打开, 除非这两个网页同源
如果没有同源策略的话, 那么在你访问B网站的同时, B网站也可以获取A网站的 Cookie
- 而如果此时的
Cookie
包含了好友信息, 账户余额等隐私, 就容易导致隐私的泄露. - 而且
Cookie
经常用来保存用户的登录状态, 如果B网站在用户登录A网站的同时获取了Cookie
, 那么B网站也能够登录A网站从而进行更多的操作
由此可见, 同源策略的存在是必要的. 否则 Cookie
能够共享, 那么上网将毫无安全性可言
1.3 同源策略的具体限制
随着时代的发展, 同源策略的限制也越来越严格
Cookie
,LocalStorage
和IndexDB
无法获取DOM
无法获得AJAX
请求的数据无法获取
虽然同源策略是必要的, 但很多时候还是会带来很多不便. 尤其是现在 web 服务器和资源服务器基本都是不同源的情况下. 所以出现了一些即使不同源, 也能获取数据的方法
2. 如何跨域
2.1 使用代理服务器进行跨域
只有浏览器上应用了同源策略, 所以即使浏览器与服务器之间的不同源访问会有限制, 但是服务器与服务器之间的不同源访问就不会有限制.
故而, 我们令代理服务器与浏览器访问的页面同源, 从而使得浏览器可以访问代理服务器, 而代理服务器又能够访问目的服务器, 最终使得浏览器能够获取目的服务器的资源. 大致流程如下图所示:
这是相应的代理服务器的 node.js
代码
// server.js 代码
const express = require('express')
const request = require('request')
const app = express()
app.listen(2333, () => {
console.log('listening 2333 port')
})
app.get('/resource', (req, res) => {
// 当收到来自浏览器的 /resourse 请求时, 将会请求指定url的资源, 并将其返还给浏览器
let url = `https://www.bilibili.com`
req.pipe(request(url)).pipe(res)
})
/*
- src
- index.html
- main.js
- style.css
- server.js
*/
app.use(express.static('./src/')) // 托管静态文件
// http://localhost:2333/index.html 相当于直接访问 index.html 页面
2.2 CORS
通过在后端设置响应头的一些属性, 从而使得跨域能够成功, 如在响应头设置
access-control-allow-origin: *
: 该字段是必须的.*
表示允许来自任何源的资源请求. 同理, 只要相应的值设置为所允许访问的源, 则可实现跨域资源共享access-control-allow-credentials: true
: 该字段可选, 表示是否允许发送cookie
给服务器, 如果不允许直接不添加该字段即可access-control-allow-headers
: 该字段可选. 如果不添加该字段的话, 则浏览器 只能获取response_header
中的cache-control
,content-language
,content-type
,expires
,last-modified
,pragma
这六个字段. 对应的属性即为浏览器额外能够获取的字段access-control-allow-methods: GET, POST, OPTIONS
: 表示请求方法只允许GET
,POST
和OPTIONS
三种
在 CORS
跨域请求中, 浏览器发送请求时会在请求头中增加一个 origin
字段, 对应的值记录的是本次请求所来自的源
2.3 JSONP
回顾一下, 我们是可以通过 script
标签获取到对应的文件的, 主要的问题是我们无法通过这个方法获取到数据. 但如果我们获取的这个 js
文件可以返回数据呢
- 在客户端设置: 可以在
script
标签中的src
属性上添加一定的参数(比如说callback=fn
, 在这之前, 需要存在一个全局函数fn
) - 在服务端设置: 如果收到的请求是相应的
js
文件的话, 则可以根据请求中的参数, 将对应的js
文件设置成fn(returnData)
的形式, 这之后返回的js
文件会被作为代码进行执行, 从而可以达到获取数据的目的
JSONP 是自己的网站上创建一个 script
标签, 去请求另一个网站的 JS
, 而这个请求所返回的数据会在自己的网站上执行
优点:
- 支持 IE
- 可以跨域
缺点: - 只有
GET
方式, 并不支持POST