美文网首页前端开发那些事儿
基本跨域方式(jsonp,服务端反向代理)

基本跨域方式(jsonp,服务端反向代理)

作者: 冷r | 来源:发表于2019-08-14 20:50 被阅读0次

跨域(cross origin resource sharing)

为什么要跨域?

客户端请求服务端的时候,为了保护服务器的资源不被其他人访问到,浏览器出台了同源策略。

同源策略

同源策略,它是由Netscape提出的一个著名的安全策略。所谓同源是指,域名,协议,端口相同

const url = 'http:/ /www.163. com'
不同源的示例
- https://www.163. com
- http://email.163.com
- http://www.163. com:8088

有很多时候,我们自己的客户端5服务器不同源、或者说我们想获得不同源服务器下的数据,那么跨域技术应用而生

常见域名后缀

  • com 国际
  • cn 中国
  • uk 英国
  • org
  • edu 教育

常见的跨域技术

** 浏览器向服务器请求的数据**

  1. JSONP
  • 原理:因为src属性的标签,不受同源策略的约束,我们可以通过动态创建带有src的标签,来访问服务器返回请求数据、结果
  1. 服务器端跨域
  2. 正向代理服务器
  3. 反向代理服务器(ngix)

jsonp 跨域

//将一个对象转成序列化字符串
function formdata(opt, callback) {
    let temp = '';
    for (let key in opt) {
        temp += key + '=' + opt[key] + '&';
    }
    if (callback != undefined) {
        temp += 'callback=' + callback;
    }
    return temp;
}

function Jsonp(url, opt, callback = 'callback') {
    // 返回一个可以链式调用的promise对象
    return new Promise((resolve, reject) => {
        // 将前端querystring查询字符串的参数,拼接到参数栏
        url = url + (url.indexOf('?') > -1 ? '' : '?') + formdata(opt, callback);
        // 动态创建script标签
        let ele = document.createElement('script');
        // 设置接口的请求地址
        ele.src = url;
        //添加到页面中
        document.body.append(ele);
        // 设置请求jsonp接口的回调
        window[callback] = result => {
            // 请求jsonp接口成功后删除该函数  ---不要污染window
            delete window[callback];
            // 从页面中删除接口动态创建的script标签
            document.body.removeChild(ele);
            // 判断接口的数据返回
            if (result) {
                resolve(result);
            } else {
                reject('服务器没有返回信息');
            }
        };
        //动态创建script标记,错误的监听
        ele.addEventListener('error', () => {
            // 请求jsonp接口成功后删除该函数  ---不要污染window
            delete window['callback'];
            // 从页面中删除接口动态创建的script标签
            document.body.removeChild(ele);
        });
    });
}

// egg后台
// Jsonp('http://127.0.0.1:7001/api', {
//     username: 'zs',
//     age: 12
// }).then(result => {
//     console.log(result);
// });

// express 后台 
Jsonp('http://127.0.0.1:3000/api', {
    username: 'zs',
    age: 12
}).then(result => {
    console.log(result, 'jsnop get');
});
  1. egg写的后台
//./app/router.js
module.exports = app => {
    const { router, controller } = app;
    let jsonp = app.jsonp();
    //必须写成let jsonp=app.jsonp()
    //不能先解构jsonp 在写到router.get上jsonp()
    router.get('/seach', jsonp, controller.home.seach);
};
  1. express 写的后台代理
const url = require('url');
const qs = require('querystring');

app.get('/api', (req, res) => {
    res.writeHead(200, { 'Access-Control-Allow-Origin': '*' });
    const ourl = url.parse(req.url);
    const oQuery = qs.parse(ourl.query);
    //判断是不是jsonp接口
    if (oQuery.callback) {
        res.end(
            oQuery.callback + '(' + JSON.stringify({ code: 1, msg: 'jsonp' }) + ')'
        );
    } else {
        res.end(JSON.stringify({ code: 1, msg: 'json' }));
    }
});

自封一个ajax

function ajax(url, params = null, type = 'GET') {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        xhr.open(type, url);
        params = formdata(params);
        if (type == 'GET' && params) {
            url += url.indexOf('?') > -1 ? '' : '?' + params ;
            xhr.send(null);
        } else if (type == 'POST') {
            xhr.setRequestHeader(
                'Content-type',
                'application/x-www-form-urlencoded'
            );
            xhr.send(params);
        }
        xhr.onreadystatechange = () => {
            if (xhr.readyState !== 4) return;
            if (xhr.status == 200) {
                resolve(JSON.parse(xhr.responseText));
            } else {
                reject(new Error('request failed'));
            }
        };
    });
}
//将一个对象转成序列化字符串
function formdata(opt, callback) {
    let temp = '';
    for (let key in opt) {
        temp += key + '=' + opt[key] + '&';
    }
    if (callback != undefined) {
        temp += 'callback=' + callback;
    }
    return temp;
}
//ajax get 请求
ajax('http://127.0.0.1:3000/api', {
    username: 'zs',
    age: 12
}).then(res => {
    console.log(res, 'ajax get');
});
//ajax post 请求
ajax(
    'http://127.0.0.1:3000/postApi', {
        username: 'zs',
        age: 12
    },
    'POST'
).then(res => {
    console.log(res, 'ajax post');
});
  1. express 写的后台代理
router.post('/postApi', (req, res) => {
    res.writeHead(200, { 'Access-Control-Allow-Origin': '*' });
    const body = req.body;
    res.end(JSON.stringify({ code: 1, msg: 'json post' ,...body}));
});

相关文章

网友评论

    本文标题:基本跨域方式(jsonp,服务端反向代理)

    本文链接:https://www.haomeiwen.com/subject/kwonjctx.html