在咱们平常开发中,常常碰到一些跨域的问题。javascript
例如www.a.com
想要获取到www.b.com
的接口或者数据。就会由于同源策略的缘由而没法获取到。html
同源策略 same-orgin policy 不一样域的客户端脚本在没有明确受权的状况下,不能读写对方的资源。前端
a.taobao.comjava
地址 | 是否能够请求 |
---|---|
a.taobao.com | 不能够-协议不一样 |
www.taobao.com | 不能够-子域不一样 |
taobao.com | 不能够-子域不一样 |
a.taobao.com:8080 | 不能够-端口不一样 |
a.taobao.com/music/ | 能够-同域 |
CORS是一种跨域的解决方案,其原理就是前台发送一个请求,而服务器就返回一个请求头受权访问。node
// 后台koa脚本
const koa = require('koa');
const bodyParser = require('koa-bodyparser');
const app = new koa();
//使用bodyParser
app.use(bodyParser());
app.use(async ctx =>{
const url = ctx.url;
if(ctx.headers.origin && ctx.query.cors){
//设置请求头
ctx.set('Access-Control-Allow-origin',ctx.headers.origin)
}
let res = {
code:0,
data:'success'
}
ctx.body = JSON.stringify(res);
})
app.listen(3000,()=>{
console.log('服务器冲起来了');
})
复制代码
后台在
node
3000的端口运行,前台在http-server
3001 端口运行git
//前台请求
var $ = (id) => document.getElementById(id);
var btn = $('button1');
var btn2 = $('button2');
function getData(callback, cors) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.responseText) {
callback(JSON.parse(xhr.responseText), xhr);
}
}
xhr.open('get', `http://127.0.0.1:3000/${cors}`);
xhr.send(null);
}
btn.addEventListener('click', () => {
getData((response) => {
console.log(`${response.data}`)
}, '');
});
btn2.addEventListener('click', () => {
getData((response) => {
console.log(`${response.data}`)
}, '?cors=1');
});
复制代码
原理github
script
进行请求经过src请求//koa
const Koa = require('koa')
const bodyParser = require('koa-bodyparser')
const app = new Koa()
// 使用bodyParser
app.use(bodyParser())
app.use(async ctx => {
const url = ctx.url
if (url.indexOf('/getData') === 0) { // 接口名称
ctx.set('Content-Type', 'application/x-javascript')
let res = {
code:0,
data:"我是一个jsonP跨域的数据!"
}
ctx.body = `${ctx.query.callback || 'jsonp'}(${JSON.stringify(res)})`
} else {
ctx.status = 404
ctx.body = '404'
}
})
app.listen(3000, () => {
console.log('服务启动,打开 http://127.0.0.1:3000/')
})
复制代码
后台在
node
3000的端口运行,前台在http-server
8081 端口运行web
/** * 自动发送 jsonp * @param {String} url * @param {Obj} data * @param {Function} callback */
function jsonp (url, data, callback) {
var funcName = getFunctionName()
data = data || {}
data.callback = funcName
url = parseUrl(url, serialize(data))
window[funcName] = function (response) {
// 这里能够看状况处理,好比若是是 jsonp 咱们能够 parse 一下
// data = JSON.parse(response)
callback(response)
}
createScript(url)
}
/** * 序列化参数 * jsonp 中参数只能是 GET 方式传递 * @param {Obj} data */
function serialize (data) {
var ret = []
Object.keys(data).forEach(item => {
ret.push(encodeURIComponent(item) + '=' + encodeURIComponent(data[item]))
})
return ret.join('&')
}
/** * 处理 URL ,把参数拼上来 * @param {String} url * @param {String} param */
function parseUrl (url, param) {
return url + (url.indexOf('?') === -1 ? '?' : '&') + param
}
/** * 必需要有一个全局函数,并且不能重名 */
function getFunctionName () {
return ('jsonp_' + Math.random()).replace('.', '')
}
/** * 建立 script 标签并插到 body 中 * @param {String} url */
function createScript (url) {
var doc = document
var script = doc.createElement('script')
script.src = url
doc.body.appendChild(script)
}
复制代码
//调用
jsonp('http://127.0.0.1:3000/getData', {id:1}, (data) => {
console.log(data)
})
复制代码
这是一个简单版的
jsonP
的实现,面试中也会经常被问到,而且手撸一个jsonP
面试
具体的一个方法实现推荐一个 github 上面的一个库 👉 实现jsonPajax
原理
咱们以三个页面为例和一个json为例
大概的交互图为这样 👇
a为请求数据
<!--a.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>我是A页面</title>
</head>
<body>
<div></div>
<script> var xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { if (xhr.readyState === 4) { console.log(xhr.responseText); } else { console.log(xhr.status, xhr.statusText); } } xhr.open('get', 'http://127.0.0.1:3002/data.json'); xhr.send(null); </script>
</body>
</html>
复制代码
b为处理数据
<!--b.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>处理数据</title>
</head>
<body>
<script> var xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { if (xhr.readyState === 4) { window.name = xhr.responseText; location.href = 'http://127.0.0.1:3001/c.html'; } else { console.log(xhr.status, xhr.statusText); } } xhr.open('get', 'data.json'); xhr.send(null); </script>
</body>
</html>
复制代码
c为更新数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>传递数据</title>
</head>
<body>
<script> parent.update(window.name); </script>
</body>
</html>
复制代码
data数据
[
{
"data": "我是一条跨域数据"
}
]
复制代码
当咱们调用a.html第一个AJAX方法的时候,毫无疑问确定是跨域的,由于端口不同
Access to XMLHttpRequest at 'http://127.0.0.1:3002/data.json' from origin 'http://127.0.0.1:3001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
接下来咱们修改一下A 的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>我是A页面</title>
</head>
<body>
<div></div>
<iframe src="http://127.0.0.1:3002/b.html" frameborder="0"></iframe>
<script> function update(data) { data = JSON.parse(data); var html = ['<ul>']; html.push(`<li>${data[0].data}</li>`); html.push('</ul>'); document.querySelector('div').innerHTML = html.join(''); } </script>
</body>
</html>
复制代码
在改变了逻辑时
a.html
嵌套了一个与接口同样端口的网页b.html
经过同端口的方式请求到了想用端口的数据,而且挂载到了全局的window.name
上,而且跳转到c.html
c.html
经过parent
调用a.html
的update
的方法并把window.name
值一同传递此时咱们就大功告成啦,页面显示出data.json
的数据
以上就是我分享的前端跨域请求方式!
写的很差,仅供参考!