在不会服务端代理之前,遇到返回Json格式数据url,是一点办法都没有,因为jsonp用不了,比如下面的数据接口
(jsonp的具体用法看我的另一篇博客https://blog.csdn.net/dreamjay1997/article/details/88669493)
其中大部分都是返回json格式的数据的,除了joke0可以用jsonp实现跨域的数据获取,所以一旦没有了服务端的帮忙,加上返回的是纯的json数据,我们就要用服务端代理来实现数据的跨域请求了,话不多说就是干!
首先,我们要有两个不同端口的应用,产生跨域的情况,(因为现在都是前后端分离了,所以跨域的情况也很常见了,所以我相信读者因该很好模拟这种情况的),从一个应用用XMLHttpRequest发送一个请求到localhost:4000/getJson,我们期望可以获取到数据(这里的ajax请求,如果你嫌麻烦的话,你也可以用fetch,axios等开源库发送请求,要方便一点)
let xhr = new XMLHttpRequest()
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.response)
}
}
xhr.open('post', 'http://localhost:4000/getJson', true)
xhr.send(JSON.stringify({
url: 'http://data.live.126.net/livechannel/sub/3.json'
}))
细心的同学可能回发现,我们在send方法中把要获取数据的url传过去了,并且用JSON把它变成了字符串,这是问了在服务端能获取到这个url,如果不把它变为字符串的话,服务端的获取会出问题
我们来看下服务端的代码,用node写个服务器,很简单的代码
const http = require('http');
http.createServer((req, res)=>{
console.log('request: ', req.url)
if(req.url === '/getJson'){
res.writeHead(200,{
'Content-Type': 'text/html',
})
res.end('你的Json数据')
}
}).listen(4000);
打开控制台的NetWork看下请求是否成功
控制台提醒我们由于浏览器的同源策略,响应被阻挡了,所以我们获取不到数据了,不急,解决方法很简单,现在服务器在我们的手里,我们只要在响应的首部加上 Access-Control-Allow-origin字段就可以了,如果赋值为*,则表示告诉浏览器任何针对我这个url的请求我都允许,你别拦着,也可以只允许特定的域名和端口访问,就告诉浏览器,我只认准他哈,其它的都给了拦下来,这里我用的是后一种
res.writeHead(200,{
'Content-Type': 'text/html',
'Access-Control-Allow-origin': 'http://localhost:3000'
})
我们在请求一次,看下结果,如果控制台中出现'你的Json数据'则表示跨域成功
果然跨域成功,获取到数据
接下来用node实现代理获取Json数据
我们只要用node的http模块,去请求目标url,然后取出数据,然后返回给客户端就行了
完整的服务器端代码,关键点有详细的解释
const http = require("http");
function getJson(url, callback) {
// 向目标url发送请求
http.get(url, function(res) {
var data = "";
// data 数据当node接收数据的时候回触发,这里要明白为什么是data += 而不是 data = 因为数据的传输不是一次到位的是,有个缓冲区,当缓冲区满了,才会发送,所以data事件是会多次触发的
res.on('data', function (chunk) {
data += chunk;
});
// 当数据接收完毕之后,会触发end事件
res.on("end", function() {
callback(data);
});
}).on("error", function() {
callback(null);
});
}
http.createServer((req, res)=>{
let data = ''
let url = ''
// 获取客户端传过来的数据
req.on('data', (chunk)=>{
data += chunk
})
// 当客户端的数据接收完毕之后会触发end事件
req.on("end", ()=>{
// 解析出url
url = JSON.parse(data).url
})
if(req.url === '/getJson'){
let promise = new Promise((resolve)=>{
// 为了获取到url之后,才向目标url请求数据,所以延时一段时间
//如果不延时url为获取到就发送请求了,因为end事件的触发是在这之后的
setTimeout(()=>{
getJson(url, (data)=>{
resolve(data)
})
}, 100)
}).then((data)=>{
res.writeHead(200,{
'Access-Control-Allow-origin': 'http://localhost:3000' // 允许跨域
})
res.end(JSON.stringify(data))
}).catch((error)=>{
console.log(error)
})
}
}).listen(4000);
console.log('server listening on port 4000')
完整客户端的代码
let xhr = new XMLHttpRequest()
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4 && xhr.status === 200) {
let data = JSON.parse(xhr.response)
console.log(JSON.parse(data))
}
}
xhr.open('post', 'http://localhost:4000/getJson', true)
xhr.send(JSON.stringify({
url: 'http://data.live.126.net/livechannel/sub/3.json'
}))
运行结果,我们可以看到
数据请求成功!!
所以以后看到数据的接口返回的是Json格式的就不用担心了,写个代理就????了