跨域实践之node代理获取Json数据

时间:2024-03-27 14:16:02

在不会服务端代理之前,遇到返回Json格式数据url,是一点办法都没有,因为jsonp用不了,比如下面的数据接口

(jsonp的具体用法看我的另一篇博客https://blog.csdn.net/dreamjay1997/article/details/88669493

跨域实践之node代理获取Json数据

跨域实践之node代理获取Json数据

 

其中大部分都是返回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看下请求是否成功

跨域实践之node代理获取Json数据

控制台提醒我们由于浏览器的同源策略,响应被阻挡了,所以我们获取不到数据了,不急,解决方法很简单,现在服务器在我们的手里,我们只要在响应的首部加上 Access-Control-Allow-origin字段就可以了,如果赋值为*,则表示告诉浏览器任何针对我这个url的请求我都允许,你别拦着,也可以只允许特定的域名和端口访问,就告诉浏览器,我只认准他哈,其它的都给了拦下来,这里我用的是后一种

        res.writeHead(200,{
            'Content-Type': 'text/html',
            'Access-Control-Allow-origin': 'http://localhost:3000'
        })

我们在请求一次,看下结果,如果控制台中出现'你的Json数据'则表示跨域成功

 

跨域实践之node代理获取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'
        }))

运行结果,我们可以看到

跨域实践之node代理获取Json数据

数据请求成功!!

所以以后看到数据的接口返回的是Json格式的就不用担心了,写个代理就????了