关于jsonp,cors跨域的那些事

一直以为以前对jsonp道理和实现已经掌握了(src不受同源策略的限制,通过新建scrpit来加入dom,并绑定回调函数来实现跨域),但是最近被问到的时候还是有种一知半解,说不全,今天来总结一下jsonp的一些难点(由于jq对jsonp的封装导致了很多不一致的地方)
有很多内容摘参考了https://mp.weixin.qq.com/s/9I...

json

JSONP 是 JSON 的一种使用模式,可以解决主流浏览器的跨域数据访问问题。其原理是根据 XmlHttpRequest 对象受到同源策略的影响,而 <script> 标签元素却不受同源策略影响,可以加载跨域服务器上的脚本,网页可以从其他来源动态产生 JSON 资料。用 JSONP 获取的不是 JSON 数据,而是可以直接运行的 JavaScript 语句。

jsonp源码

jsonp({
    url: 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',
    type: 'get',
    data:{
        wd: 'jsonp'
    },
    callback: 'cb',
    success: function (data) { 
        console.log(data) 
    }
});

function jsonp (options) {
    let url = options.url
    let data = options.data
    
    let oBody = document.getElementsByTagName('body')[0]
    let oScript = document.createElement('script')
    
    let callbackName = 'cb' + (~~(Math.random()*0xffffff)).toString(16)
    window[callbackName] = function (result) {
        options.success(result)        
    }
    data[options.callback] = callbackName
    
    oScript
        .setAttribute('src', url + '?' + format(data))
    oBody.append(oScript)
}
function format(data) {
    let str = ''
    for (var p in data) {
        str += encodeURIComponent(p) + '=' + encodeURIComponent(data[p]) + '&'
    }
    return str
}

我记得以前封装的时候一直不是很理解这个callback名字的道理,不是直接读取options的callback就行了吗,后来才知道这个是为了在默认情况下callbackName为了不重名,对其进行了改写,后端代码直接读取callbackName就行。

后端读取jsonp

app.get("https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su", function(req, res) {
    console.log("server accept: ", req.query.name, req.query.id)
    var data = "{" + "name:'" + req.query.name + " - server 3001 process'," + "id:'" + req.query.id + " - server 3001 process'" +"}"
    var callback = req.query.callback
    var jsonp = callback + '(' + data + ')'
    console.log(jsonp)
    res.send(jsonp)
    res.end()
})

这里对data数据进行了序列化,data 中字符串拼接,不能直接将 JSON 格式的 data 直接传给回调函数,否则会发生编译错误: parsererror Error: jsonpCallback was not called。
注意:jsonp返回的不是json数据,而是一段可以立即执行的js代码,所以不会像 ajax 的 XmlHttpRequest 那样可以监听不同事件对数据进行不同处理。由于jq的jsonp进行了封装,所以才看起来想ajax一样,有错误回调,其实jsonp的短板就是不能发post请求和不能注册success,error等监听函数

cors跨域

现在用得比较多的跨域是cors,以前的flash和iframe跨域都存在的问题,这是一种新规范。所谓同源策略的限制其实是跨域请求并非是浏览器限制了发起跨站请求,而是请求可以正常发起,到达服务器端,但是服务器返回的结果会被浏览器拦截。

原生封装cors

function createCORSRequest(method, url) {
  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) {

    // "withCredentials"属性是XMLHTTPRequest2中独有的
    xhr.open(method, url, true);

  } else if (typeof XDomainRequest != "undefined") {

    // 检测是否XDomainRequest可用
    xhr = new XDomainRequest();
    xhr.open(method, url);

  } else {

    // 看起来CORS根本不被支持
    xhr = null;

  }
  return xhr;
}

var xhr = createCORSRequest('GET', url);
if (!xhr) {
  throw new Error('CORS not supported');
}
// 绝大多数情况下,我们只需要和onload及onerror打交道,就像下面这样:

xhr.onload = function() {
 var responseText = xhr.responseText;
 console.log(responseText);
 // 继续其它代码
};

xhr.onerror = function() {
  console.log('There was an error!');
};

对比下元素ajax

function AJAX(json) {
    var url = json.url,
        method = json.method,
        flag = json.flag,
        data = json.data,
        callBack = json.callBack,
        xhr = null;
    if(window.XMLHttpRequest) {
        xhr = new window.XMLHttpRequest();
    }else {
        xhr = new ActiveXObject('Mircosoft.XMLHTTP');
    }            
    if(method == 'get') {
        url += '?' + data + new Date().getTime(); 
        xhr.open('get', url, flag);
    }else {
        xhr.open('post', url, flag);
    }
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            // 数据已经可用了
            callBack(xhr.responseText);
        }
    }
    if(method == 'get') {
        xhr.send();
    }else {
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urle');
        xhr.send(data);
    }    
}

服务器应答cors

app.post('/cors', function(req, res) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    var data = {
        name: req.body.name + ' - server 3001 cors process',
        id: req.body.id + ' - server 3001 cors process'
    }
    console.log(data)
    res.send(data)
    res.end()
})

哈,感谢你的观看,喜欢的话可以点赞,收藏~~~
如果有什么写错的地方,欢迎大家指出,一起学习进步~~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Axios可以通过使用JSONP来解决跨域问题。JSONPJSON with Padding的缩写,是一种解决跨域请求的方法。JSONP通过在请求URL中传递一个回调函数名称,服务器端将数据包装在该回调函数的调用中返回给客户端,客户端再通过该函数接收并处理数据,这样就实现了跨域请求。 Axios中可以通过设置`jsonp: 'callback'`来开启JSONP跨域请求,其中`callback`是回调函数的名称。例如: ``` axios({ method: 'get', url: 'http://example.com/data', params: { id: 123 }, jsonp: 'callback' }) .then(response => { console.log(response.data) }) .catch(error => { console.log(error) }) ``` 在请求中设置了`params`参数,表示将该参数传递到服务器端,服务器端可以通过该参数返回相应的数据。同时,通过设置`jsonp: 'callback'`来开启JSONP请求,并指定回调函数的名称为`callback`。 在服务器端,需要将数据包装在回调函数的调用中返回给客户端。以Node.js为例,代码如下: ``` var express = require('express'); var app = express(); app.get('/data', function (req, res) { var id = req.query.id; var data = { id: id, name: 'John' }; var callback = req.query.callback; res.send(callback + '(' + JSON.stringify(data) + ')'); }); app.listen(3000, function () { console.log('Example app listening on port 3000!'); }); ``` 在上面的代码中,首先获取了客户端传递过来的`id`参数,然后构造数据`data`,最后获取客户端传递过来的回调函数名称`callback`,将数据包装在该回调函数的调用中返回给客户端。 通过上述方式,就可以使用Axios的JSONP功能来解决跨域请求了。 ### 回答2: Axios是一个非常流行的JavaScript库,它专门用于发送HTTP请求。然而,由于同源策略的限制,我们在使用Axios发送请求时,很容易碰到浏览器的跨域请求限制。在这种情况下,我们可以考虑使用Axios Jsonp来解决跨域问题。 JSONPJSON Padding)是一种解决跨域问题的方式,它是通过不同的网址来加载一个JavaScript文件,该文件载入后会执行我们在网址中传入的回调函数,并且将我们需要的JSON数据作为参数传递给回调函数。通常情况下,我们可以通过动态创建一个<script>元素来实现JSONP请求。 在使用Axios Jsonp解决跨域问题时,我们需要先引入Jsonp插件,在Vue项目中,我们可以通过npm来安装: ``` npm i vue-jsonp --save-dev ``` 安装完成后,我们需要在main.js中将Jsonp插件引入: ``` import Vue from 'vue' import Jsonp from 'vue-jsonp' Vue.use(Jsonp) ``` 接下来,在需要发送Jsonp请求的地方,我们可以使用Axios的jsonp方法来实现: ``` this.$jsonp(url, { param: 'callback' }).then((response) => { console.log(response.data) }).catch((error) => { console.log(error) }) ``` 在这个例子中,我们使用了this.$jsonp方法来发送请求,并且指定了callback参数,这个参数在后台接受到请求后用来充当回调函数的名称。使用Axios Jsonp可以很方便地解决跨域问题,但是由于Jsonp本身的局限性,它也存在一些缺点。比如Jsonp只支持GET请求,无法使用POST等其他请求方法。同时,也存在安全性问题,因为Jsonp并不是一个真正的Ajax请求,所以无法像Ajax那样对请求进行全面的验证。如果需要更加严格的安全控制,我们需要考虑使用CORS(Cross-Origin Resource Sharing)或者代理来解决跨域问题。 ### 回答3: Axios 是一款流行的 HTTP 客户端库,它支持浏览器和 node.js 平台。它提供了很多接口来执行各种 HTTP 请求,例如 GET、POST、PUT、DELETE 等。但在浏览器中,由于跨域策略的限制,发送跨域请求会受到限制。浏览器限制的跨域请求包括 XMLHttpRequest、Fetch、Ajax 等。 解决这个问题的一种方法是使用 JSONP,它是浏览器的一种跨域解决方案,允许在客户端从不同的域名请求数据。JSONP 的原理是通过动态创建 script 标签,将请求的数据封装在一个函数调用中,服务器返回的数据会被该函数接收并解析。在客户端通过 script 标签加载服务器返回的 js 文件,客户端收到 js 文件后直接执行其中的代码。因为返回的是一段 JavaScript 代码,所以不存在跨域问题。 Axios 提供了一个可以发送 JSONP 请求的接口,这个接口是 JSONP 接口的 promise 化版本。Axios 的jsonp接口主要有两个参数,一个是url,另一个则是用于配置jsonp的一些选项和回调函数。 下面是 axios jsonp 的使用示例: ``` axios.jsonp('http://server.com/api', { params: { // 设置请求参数 name: 'apple', count: 10 }, jsonpCallback: 'callback', // 回调函数名字 timeout: 5000 // 超时时间 }) .then(function(response){ console.log(response); }) .catch(function(error){ console.log(error); }); ``` 在传递的配置选项中,`jsonpCallback` 是必选的选项,它指定了回调函数的函数名。服务器返回的数据应该该函数名作为函数调用,并将请求的数据作为参数传入。在完成请求的时候,Axios 会调用这个函数来解析返回的数据。 Axios 通过动态创建 script 标签的方式发送 JSONP 请求,解决了同源策略限制下的跨域问题。同时,Axios 对 JSONP 的支持也使得开发者能够更加方便地获取数据,轻松构建跨域 Web 应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值