注: 文章摘自 写Bug - 思否javascript
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,若是缺乏了同源策略,则浏览器的正常功能可能都会受到影响。能够说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具备相同的协议(protocol),主机(host)和端口号(port)html
例: 在 vue.config.js
文件中添加以下配置前端
const webpack = require('webpack');
module.exports = {
devServer: {
open: true, // 在 DevServer 启动, 且第一次构建完时自动打开网页
port: 8080, // 端口号
proxy: { // 设置代理
'/api': { // 网关地址
target: 'https://test.com', // 接口的域名
ws: true, // 启用 websocket
secure: false, // 若是是 https 协议,须要配置这个参数
// 开启代理:在本地会建立一个虚拟服务端,而后发送请求的数据,并同时接收请求的数据,
// 这样服务端和服务端进行数据的交互就不会有跨域问题
changOrigin: true, // 跨域需开启
pathRewrite: { // 重写地址
'^/api': '' // 将前缀 '/api' 转为 '/'
}
}
}
}
}
复制代码
注: 因为本质上 script 加载资源的方式是GET, 因此 JSONP 只能用于 GET 请求vue
在HTML标签里,一些标签好比 script、img 这样的获取资源的标签是没有跨域限制的,利用这一点,咱们能够这样干:java
// 处理成功失败返回格式的工具
const {successBody} = require('../utli')
class CrossDomain {
static async jsonp (ctx) {
// 前端传过来的参数
const query = ctx.request.query
// 设置一个cookies
ctx.cookies.set('tokenId', '1')
// query.cb是先后端约定的方法名字,其实就是后端返回一个直接执行的方法给前端,因为前端是用script标签发起的请求,因此返回了这个方法后至关于立马执行,而且把要返回的数据放在方法的参数里。
ctx.body = `${query.cb}(${JSON.stringify(successBody({msg: query.msg}, 'success'))})`
}
}
module.exports = CrossDomain;
复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script type='text/javascript'>
// 后端返回直接执行的方法,至关于执行这个方法,因为后端把返回的数据放在方法的参数里,因此这里能拿到res。
window.jsonpCb = function (res) {
console.log(res)
}
</script>
<script src='http://localhost:9871/api/jsonp?msg=helloJsonp&cb=jsonpCb' type='text/javascript'></script>
</body>
</html>
复制代码
const request = ({url, data}) => {
return new Promise((resolve, reject) => {
// 处理传参成xx=yy&aa=bb的形式
const handleData = (data) => {
const keys = Object.keys(data)
const keysLen = keys.length
return keys.reduce((pre, cur, index) => {
const value = data[cur]
const flag = index !== keysLen - 1 ? '&' : ''
return `${pre}${cur}=${value}${flag}`
}, '')
}
// 动态建立script标签
const script = document.createElement('script')
// 接口返回的数据获取
window.jsonpCb = (res) => {
document.body.removeChild(script)
delete window.jsonpCb
resolve(res)
}
script.src = `${url}?${handleData(data)}&cb=jsonpCb`
document.body.appendChild(script)
})
}
// 使用方式
request({
url: 'http://localhost:9871/api/jsonp',
data: {
// 传参
msg: 'helloJsonp'
}
}).then(res => {
console.log(res)
});
复制代码
// 处理成功失败返回格式的工具
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'
}
});
复制代码
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)跨域资源共享 CORS 详解。看名字就知道这是处理跨域问题的标准作法。CORS有两种请求,简单请求和非简单请求。node
只要同时知足如下两大条件,就属于简单请求。webpack
请求方法是如下三种方法之一:web
HTTP的头信息不超出如下几种字段:json
后端segmentfault
// 处理成功失败返回格式的工具
const {successBody} = require('../utli')
class CrossDomain {
static async cors (ctx) {
const query = ctx.request.query
// *时cookie不会在http请求中带上
ctx.set('Access-Control-Allow-Origin', '*')
ctx.cookies.set('tokenId', '2')
ctx.body = successBody({msg: query.msg}, 'success')
}
}
module.exports = CrossDomain;
复制代码
前端什么也不用干,就是正常发请求就能够,若是须要带cookie的话,先后端都要设置一下
fetch(`http://localhost:9871/api/cors?msg=helloCors`, {
// 须要带上cookie
credentials: 'include',
// 这里添加额外的headers来触发非简单请求
headers: {
't': 'extra headers'
}
}).then(res => {
console.log(res)
});
复制代码