浏览器有同源策略,协议 域名 端口不一样,就不能互相访问资源javascript
function show(data){
console.log(data)
}
复制代码
<script src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=lol&cb=show"></script>
// cb就是厚度返回的执行函数名
复制代码
//后端会返回
show({
p: false
q: "lol"
s: (10) ["lol官网", "lol手游", "lol转区", "lol是什么意思",
"lol半价吧", "lol春季赛", "lol转区系统"]
})
复制代码
//使用
jsonp({
url:'xxx',
params:{wd:'xxx'},
cb:'xx'
}).then(res=>console.log(data))
复制代码
let jsonp = ({url,params,cb})=>{
return new Promise((resolve,reject)=>{
//1.建立一个script标签
let script = document.createElement('script')
//3. 将cb挂载到全局中,后端会返回cb(数据),接收数据返回数据便可
window[cb]=function(data){
resolve(data)
//4. 记得将增长到script删除
script.remove()
}
//2.将params和cb转化成wd=xxx&cb=xxx
params = {...params,cb}
let arr = []
for(let key in params){
arr.push(`${key}=${params[key]}`)
}
script.src=url+'?'+arr.join('&')
document.body.appendChild(script)
})
}
复制代码
let express = require('express')
let app = new express()
app.get('/say',function(req,res){
let {wd,cb}=req.query
res.end(`${cb}('返回的数据')`)
})
app.listen(3000,function(){console.log('启动')})
复制代码
这是一个后端的解决方案,能够用node来模拟html
启动两个服务器,一个3000端口,一个4000端口java
3000端口启动一个网页,在网页中访问4000端口的资源node
const express = require('express');
let app = express();
//将这个目录下的资源以静态资源的方式提供访问
app.use(express.static(__dirname));
app.listen(3000, function () {
console.log('3000启动');
});
复制代码
// index.html
<script> let xhr = new XMLHttpRequest(); xhr.open('get', 'http://localhost:4000/say'); xhr.onreadystatechange = function () { if(xhr.readyState === 4 && 300 >= xhr.status&&xhr.status >= 200) { console.log(xhr.response); } }; xhr.send(); </script>
复制代码
浏览器输入:localhost:3000/index.html
,会警告跨域问题git
而且端口:4000的服务是有接受到端口3000的请求的,只是返回的内容被浏览器屏蔽了github
提示:Access-Control-Allow-Origin
没有容许http://localhost:3000
访问资源,能够ajax
//设置容许访问的域名的白名单
let whiteList = ['http://localhost:3000'];
app.use(function (req, res, next) {
//获取请求的origin
let origin = req.headers.origin;
if (whiteList.includes(origin)) {
//若是在白名单内,则容许他访问
res.setHeader('Access-Control-Allow-Origin', origin);
}
next();
});
复制代码
但这种方式只容许get,post,head这种简单的请求,若是是put呢express
xhr.open('put','http://localhost:3000/say')
复制代码
app.put('/say',function(req,res){
res.end('post请求')
})
复制代码
浏览器报错,咱们须要后端设置容许put请求json
app.use(function(req,res){
res.setHeader('Access-Control-Allow-Methods','PUT')//记得大写
})
复制代码
若是咱们在请求头中加点信息呢,后端
xhr.setRequestHeader('name','huzhiwu')
复制代码
浏览器警告说,须要后端容许那个请求头
但端口4000能接受到这个请求头
设置容许的请求头
res.setHeaders('Access-Control-Allow-Headers','name')
复制代码
咱们在端口4000的服务中,打印每次请求的method
app.use(function(req,res){
console.log(req.method)
})
复制代码
刷新浏览器时,会发现。端口4000打印了两个method
options是浏览器在发现跨域时,会先向服务器一个预检请求,该方法返回容许访问的methods,若是请求方法不在methods中则报错,存在的话,就发送真正的请求
这样子每次发送一个请求,实际发送了两个请求,是比较耗性能的,若是咱们的方法不常常改变,可让
浏览器在一段时间内预检一次就够了
req.setHeader('Access-Control-Max-Age',5)//单位秒
复制代码
let xhr = new XMLHttpRequest();
xhr.open('put', 'http://localhost:4000/say');
document.cookie='name=huzhiwu'
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && 300 >= xhr.status && xhr.status >= 200) {
console.log(xhr.response);
}
};
xhr.send();
复制代码
// 端口4000的服务器
app.use(function(req,res){
console.log(req.headers)
})
复制代码
发现没有咱们携带的cookie
在ajax请求中增长
xhr.withCredentials = true;
复制代码
浏览器又报错了
在node中设置容许跨域携带cookie便可
res.serHeader('Access-Control-Allow-Credentials')
复制代码
app.put('/say',function(req,res){
res.setHeader('name','huzhiwu')
res.end('put')
})
复制代码
let xhr = new XMLHttpRequest();
xhr.open('put', 'http://localhost:4000/say');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && 300 >= xhr.status && xhr.status >= 200) {
console.log(xhr.getResponseHeader('name'));
}
};
xhr.send();
复制代码
浏览器又报错
浏览器以为服务器返回给你的请求头不安全,不给你获取
在node中设置
res.setHeader('Access-Control-Expose-Headers','name')
复制代码
//容许哪源能够访问我
res.setHeader('Access-Control-Allow-Origin',origin)
//容许那个方法能够访问我
res.setHeader('Access-Control-Allow-Methods','PUT')
//预检存活时间
res.setHeader('Access-Control-Max-Age',5)//单位秒
//容许请求携带的headers
res.setHeader('Access-Control-Allow-Headers','name')
//容许浏览器获取服务器返回的headers
res.setHeader('Access-Control-Expose-Headers','name')
复制代码
页面跟嵌套在iframe中的页面通讯
分别开启a,b两个服务,端口号分别是3000,4000
//a.js b.js
const express = require('express');
const app = express();
app.use(express.static(__dirname));
app.listen(4000/3000, function () {
console.log('4000/3000启动');
});
复制代码
a页面放在3000端口,b页面放在4000端口
在b页面中引用a页面
<body>
<iframe src='http://localhost:3000/a.html' id='aIframe' onload='load()'>
</iframe>
<script> function load(){ let frame = document.getElementById('aIframe') //给嵌套在iframe中的页面的window发送信息 //第二个参数是origin frame.contentWindow.postMessage('你好我是b页面','http://localhost:3000/a.html') } //b页面监听来自a页面的信息 window.onmessage=function(e){ console.log(e.data) } </script>
</body>
复制代码
在a页面中监听b页面的信息
window.onmessage=function(e){
console.log(e.data)
//收到信息后给b页面发送信息,
e.source.postMessage('你好,我是a页面',e.origin)
}
复制代码
浏览器打开http://localhost:4000/b.html
发送信息
window.postMessage('信息',orign)
复制代码
接收信息
window.onmessage=function(e){
console.log(e.data)
}
复制代码
window.name默认为空字符串,咱们能够在name中存入信息,跨域访问他
http://localhost:3000
http://localhost:4000
开启两个服务器,分别是3000和4000端口
c页面
<script> window.name='我是c页面' </sctript> 复制代码
a页面
<body>
<iframe src='http://localhost:4000/c.html' id='frame' onload='load()'>
</iframe>
<script> let first=true let frame = document.getElementById('frame') function load(){ //第一次加载完成,当即将frame的src转到同源下 if(first){ frame.src='http://localhost:3000/b.html' first=false; }else{ //同源下,便可访问name console.log(frame.contentWindow.name) } } </script>
</body>
复制代码
当网络请求跨域时,可使用代理。
服务器访问服务器没有跨域问题.因此,咱们的作法是利用中间的代理浏览器向目标浏览器发请求。
a.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
//将请求转发到另外一个服务器
const apiProxy = createProxyMiddleware('/say', {
target: 'http://localhost:4000',
});
const app = express();
app.use(express.static(__dirname));
app.use(apiProxy);
app.listen(3000, function () {
console.log('3000启动');
});
复制代码
b.js
const express = require('express');
const app = express();
app.use(express.static(__dirname));
app.get('/say', function (req, res) {
res.end('我是b服务器的信息');
});
app.listen(4000, function () {
console.log('4000启动');
});
复制代码
<script> let xhr = new XMLHttpRequest(); xhr.open('get', 'http://localhost:3000/say'); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && 300 >= xhr.status && xhr.status >= 200) { console.log(xhr.response); } }; xhr.send(); </script>
复制代码
http-proxy-middleware的更多参数请看https://github.com/chimurai/http-proxy-middleware
举个例子www.video.baidu.com和www.map.baidu.com是两个二级域名,
// www.map.baidu.com
<body>
<script> window.name='huzhiwu' </script>
</body>
// www.video.baidu.com
<body>
<iframe src='www.map.baidu.com' id='frame' onload='load'>
</iframe>
<script> function load(){ let frame = document.getElementById('frame') console.log(frame.contentWindow.name)//跨域访问不到 } </script>
</body>
复制代码
由于跨域访问不到,
但只要在两个二级域名中加个document.domain='baidu.com'
便可互相访问
做者:胡志武
时间:2020/05/06
若是喜欢的话,请点个赞吧,若是有错漏处,请指正