原文: https://juejin.im/post/5f1146a8e51d453dec11861f
跨域,指的是从一个域名去请求另外一个域名的资源。即跨域名请求!跨域时,浏览器不能执行其他域名网站的脚本,是由浏览器的同源策略造成的,是浏览器施加的安全限制。
跨域的严格一点来说就是只要协议,域名,端口有任何一个的不同,就被当作是跨域。
加载图片 CSS JS 可无视同源策略
提示:我们有时候就会引入一些cdn 的js和css等,这些地址肯定不是同源的,但却可以使用。
另外,有些图片如果做了防盗链限制(服务端上的处理)的话,就不能使用。
Ohmygod!那为什么图片 CSS JS 可无视同源策略???
浏览器这样做,都是有一定的考虑的,都是为了有一些功能,比如说:
可用于统计打点,可使用第三方统计服务
``````
可使用CDN,CDN一般都是外域
可实现JSONP
所有的跨域,都必须经过server端允许和配合 未经server端允许就实现跨域,说明浏览器有漏洞,危险信号
那么解决跨域问题的几个办法来了!!!
No.1 JSONP
首先,我们要先明白
访问 www.baidu.com/,服务端一定会返回一个… ?
服务端可以任意动态拼接数据返回,只要符合html格式要求。
同理于:
服务端也许并不是返回一个getData.js静态文件,而是服务端通过拼接任何数据返回给你,只要拼接的数据格式不报错就行。
那么,我们已经知道了
复制代码
代码讲解:
前端通过请求
http://localhost:8002/jsonp.js
并传入相应参数 ?username=xxx&callback=abc
后端收到请求,根据路径和参数等信息,动态处理拼接出jsonp.js
文件返回给前端。
前端根据jsonp.js
文件内容,执行 window.abc
函数,输出内部数据。
No.2 CORS
CORS是一个w3c标准,全称是"跨域资源共享"(Cross-origin resource sharing),当一个请求url的协议,域名,端口三者之间任意与当前页面地址不同即为跨域.它允许浏览器向跨源服务器发送XMLHttpRequest请求,从而克服AJAX只能同源使用的限制.
原理:
服务器对于 CORS
的支持,主要就是通过设置 Access-Control-Allow-Origin
来进行的。 如果浏览器检测到相应的设置,就可以允许 Ajax
进行跨域的访问。
浏览器将CORS请求分为两类:简单请求和非简单请求 只要满足以下两大条件,就属于简单请求:
请求方法是以下三种方法之一:HEAD ``````GET``````POST
HTTP的头信息不超出以下几种字段:Accept``````Accept-Language``````Content-Language``````Last-Event-ID``````Content-Type
:只限于三个值 application/x-www-form-urlencoded
、multipart/form-data
、 text/plain
不同时满足上面两个条件,就是非简单请求
代码简易示例: CORS - 服务器设置 http header
// 第二个参数填写允许跨域的域名称,不建议直接写"*"
response.setHeader("Access-Control-Allow-Origin","http://localhost:8080");
response.setHeader("Access-Control-Allow-Headers","X-Requested-With");
response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
// 接收跨域的cookie
response.setHeader("Access-Control-Allow-Credentials","true");
复制代码
No.3 通过修改document.domain
来跨域*将子域和主域的 document.domain
设为同一个主域。 前提条件:这两个域名必须属于同一个基础域名,而且所用的协议,端口都要一致,否则无法使用document.domain
来进行跨域。 详细信息请看
No.4 使用window.name来进行跨域
window 对象有个name属性,该属性有个特征:即在一个窗口( window
)的生命周期内,窗口载入的所有页面都是共享一个 window.name
的,每个页面对window.name
都有读写的权限, window.name
是持久存在一个窗口载入过的所有页面中的。
No.5 使用HTML5
中新引进的window.postMessage方法来跨域传送数据
window.postMessage()是HTML5的一个接口,专注实现不同窗口不同页面的跨域通讯。
代码示例发送方:
复制代码
代码示例接收方:
我是http://crossdomain.com:9099
复制代码
No.6 iframe加form
JSONP只能发送GET请求,因为本质上script加载资源就是GET。如果要发送POST请求可以如下
后端代码:
// 处理成功失败返回格式的工具
const {successBody} = require('../utli')
class CrossDomain {
static async iframePost (ctx) {
let postData = ctx.request.body
console.log(postData)
ctx.body = successBody({postData: postData}, 'success')
}
}
module.exports = CrossDomain
复制代码
前端代码:
const requestPost = ({url, data}) => {
// 首先创建一个用来发送数据的iframe.
const iframe = document.createElement('iframe')
iframe.name = 'iframePost'
iframe.style.display = 'none'
document.body.appendChild(iframe)
const form = document.createElement('form')
const node = document.createElement('input')
// 注册iframe的load事件处理程序,如果你需要在响应返回时执行一些操作的话.
iframe.addEventListener('load', function () {
console.log('post success')
})
form.action = url
// 在指定的iframe中执行form
form.target = iframe.name
form.method = 'post'
for (let name in data) {
node.name = name
node.value = data[name].toString()
form.appendChild(node.cloneNode())
}
// 表单元素需要添加到主文档中.
form.style.display = 'none'
document.body.appendChild(form)
form.submit()
// 表单提交后,就可以删除这个表单,不影响下次的数据发送.
document.body.removeChild(form)
}
// 使用方式
requestPost({
url: 'http://localhost:9871/api/iframePost',
data: {
msg: 'helloIframePost'
}
})
复制代码
No.7 代理 Nginx配置
server{
# 监听9099端口
listen 9099;
# 域名是localhost
server_name localhost;
#凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://localhost:9871
location ^~ /api {
proxy_pass http://localhost:9871;
}
}
复制代码
// 请求的时候直接用回前端这边的域名http://localhost:9099,这就不会跨域,然后Nginx监听到凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://localhost:9871
fetch('http://localhost:9099/api/iframePost', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
msg: 'helloIframePost'
})
})
复制代码
有想了解更多前端的技术可以加Q群:1093606290
有想了解更多的小伙伴可以加Q群链接里面看一下,应该对你们能够有所帮助。