关于jsonp:方法如何批量把手机号码存入手机通讯录

题目中的问题,能够通过软件,金芝号码提取导入助手,来实现,你能够在电脑浏览器搜一上来安一个。对于销售人员来讲,有时候会接到下面传来的一份excel表格,外面就是有大量的人名和手机号码。这个时候咱们可能须要把这些人都存入到手机通讯录外面不便咱们之后的工作。然而想把几百个、几千个甚至上万个的联系人导入手机通讯录,如果手动去把人名和11位号码一个个输出手机,数量多的话工作量太大了,是很不事实的。那么咱们天然会问:如何批量把手机号码存入手机通讯录?上面演示的办法非常简单实用,借助软件,金芝号码提取导入助手,就能够一键疾速实现。 首先,关上软件“金芝号码提取导入助手”,找到下面对应功能模块:手机号码导入手机通讯录。只须要简略的几步,就能够轻松搞定。 1、把你的人名和手机号码筹备好,各自一行一列,见下图。如果没有人名,那么能够用手机号码代替,也能够应用这个软件外面自带的“人名随机生成性能”。 2、把你的表格里的人名和手机号码,别离复+制好,粘贴到软件“金芝号码提取导入助手”上。点软件上的“生成通信”,即可把文本转换成“手机通讯录数据”,倡议把这个转换好的文件,保留到“电脑桌面”好找,并写个简略好记的名字比方666,保留好。见下图。 3、下一步就是把电脑上的“通讯录”文件发送到手机上,常见的两种模式:能够借助电脑“扣扣”或者电脑徽信发送给您的手机“扣扣”或者手机徽信。见下图。 4、拿出手机,关上手机上承受到的文件,顺着手机的提醒一步步操作即可,见下图。安卓手机:用其余形式关上--抉择“联系人”、“电话本”、“通讯录”等选项--确定导入。苹果手机:用其余形式关上--抉择“通讯录”--存储。操作很简略的过程,如果导入的数量较多,须要稍等一下,关上手机通讯录,就发现曾经存好了。 附加:除了下面的把手机号码批量一键导入手机通讯录以外,金芝号码提取导入助手,还具备“手机号码提取”性能,就是当你关上一个excel表格外面含有大量芜杂的文本(比方手机号码、座机号码、人名、字母等混淆的货色),那么这个软件能够独自批量把11位手机号码提取进去,其余的芜杂文本全副主动删除。你将失去的是洁净的一行一列的手机号码。这个将不便您更好地整顿您的资料,为后面的工作:批量把手机号码存入手机通讯录,更好地服务。此外还有,号码去除反复、号码打乱程序、号码三网拆散等多种丰盛的性能,多方面贴心帮您更好地整顿资料。 提醒:这个的软件是绿色释怀没毒的,如果在电脑上装置软件的过程中,遇到杀毒软件提醒说“有危险”之类,或者被删除了,这属于误报的。您能够抉择“增加信赖”或“找回被隔离文件”“复原”“不再查杀”。或者很简略的解决办法是,您抉择齐全退出电脑右下角的杀毒软件,再次装置这个的软件即可。 总结:工欲善其事必先利其器,好的工具能助解放您的双手,在遇到看似简单的问题的时候不要慌,与其应用蛮力去节约很多的工夫和精力,不如找个简略便当的工具去帮您节约更多的工夫,把无限的工作工夫花在更有意义的局部上。金芝号码提取导入助手,你能够在电脑浏览器搜寻一下它的名字去安一个,能够解决这个问题:如何批量把手机号码存入手机通讯录,一万个号码导入手机通讯录仅须要1分钟,那是你手动存储的速度远远无奈等量齐观的。

November 23, 2021 · 1 min · jiezi

关于jsonp:剖析整数反序输出

/*#include<iostream>// . 编写一个程序,要求输出一个整数,将各位数字反序后输入。using namespace std;int main(){ int x,ox;int bw,sw,gw;cout<<"请输出一个整数:"<<endl;cin>>x;bw=x%100; sw=x%10;gw=x%1;ox=gw*100+sw*10+bw*1;cout<<"取反后数字为:"<<ox<<endl;system("pause");return 0;} */ using namespace std;int main(){ int n,right_digit,newnum=0; cout<<"请输出整数值:"<<endl; cin>>n; cout<<"反序输入数据为:"<<endl; do { right_digit=n%10; newnum=newnum*10+right_digit; n/=10;}while (n); cout<<newnum<<endl; system("PAUSE"); return 0;}

October 22, 2021 · 1 min · jiezi

一文读懂JSONP原理

跨域为什么会出现跨域? 因为浏览器有同源策略的限制,同源策略是浏览器最核心最基础的安全策略。端口,协议,域名,有一者不同就会出现跨域的问题。解决跨域的方式JSONPCORSJSONP怎样解决跨域?所谓的JSONP解决跨域问题就是前端在合适的时期动态添加一个<script>标签,请求后端给的接口带上一个回调函数。 因为<script>标签不受浏览器同源策略的限制。 手摸手带你解开JSONP的原理实现JSONP跨域和JSONP原理的几步 **前端**前端先定义一个回调函数<script type="text/javascript" charset="utf-8"> function callback(data){ console.log(data) }</script>2.在合适的阶段通过<script>标签请求后端给出的地址带上callback回调参数 <script src="http://192.168.1.107:3000?callback=callback" type="text/javascript" charset="utf-8"></script>后端 开启一个接口服务var express = require('express');var app = express();app.get('/',function(req,res,next){ res.end("ok")})app.listen(3000,function(){ console.log('JSONP') })2.等前端请求接口的时候,获取请求的参数的回调 app.get('/',function(req,res,next){ var callback = req.query.callback; })3.最后后端把所需的数据放到获取到的回调函数参数内,返回给前端(返回的是字符串),浏览器会把它解析为js执行 app.get('/',function(req,res,next){ var callback = req.query.callback; //模拟所需的数据 var data = { err_ok:0, message:"请求成功", data:{ name:"july", age:21 } } res.end(`${callback}(${JSON.stringify(data)})`) })最终后端代码 var express = require('express');var app = express();app.get('/',function(req,res,next){ var callback = req.query.callback; //模拟所需的数据 var data = { err_ok:0, message:"请求成功", data:{ name:"july", age:21 } } res.end(`${callback}(${JSON.stringify(data)})`) })app.listen(3000,function(){ console.log('JSONP') })最终前端的代码 ...

May 7, 2019 · 1 min · jiezi

vue-music QQ音乐获取Vkey方法

方法一###(有点问题)利用axios伪造,抓取的网页版qq音乐的接口,但这个接口有瑕疵…能获取到Vkey,但不是每一首歌曲都能正常播放…后来发现网页版音乐中每个歌曲的播放地址的域名不是都一样的,不能播放的歌曲有可能是这个接口不对…还没找到解决办法http://isure.stream.qqmusic.q…song.jsexport function createSong(musicData, songVkey) { return new Song({ id: musicData.songid, mid: musicData.songmid, singer: filterSinger(musicData.singer), name: musicData.songname, album: musicData.albumname, duration: musicData.interval, image: https://y.gtimg.cn/music/photo_new/T002R300x300M000${musicData.albummid}.jpg?max_age=2592000, url: http://isure.stream.qqmusic.qq.com/C400${musicData.songmid}.m4a?guid=9244517832&amp;vkey=${songVkey}&amp;uin=0&amp;fromtag=66 })}singer.jsexport function getSongVkey(songmid) { const url = ‘/api/getSongVkey’ const data = Object.assign({}, commonParams, { songmid: songmid, notice: 0, platform: ‘yqq.json’, needNewCode: 0, format: ‘json’, data: {“req_0”:{“module”:“vkey.GetVkeyServer”,“method”:“CgiGetVkey”,“param”:{“guid”:“9244517832”,“songmid”:[“001Qu4I30eVFYb”],“songtype”:[0],“uin”:“0”,“loginflag”:1,“platform”:“20”}},“comm”:{“uin”:0,“format”:“json”,“ct”:24,“cv”:0}} }) return axios.get(url, { params: data }).then((res) => { return Promise.resolve(res.data) })}webpack.dev.configapp.get(’/api/getSongVkey’, function (req, res) { var url = ‘https://u.y.qq.com/cgi-bin/musicu.fcg' axios.get(url, { headers: { referer: ‘https://u.y.qq.com/', host: ‘u.y.qq.com’ }, params: req.query }).then((response) => { res.json(response.data) }).catch((e) => { console.log(e) }) })singer-detail_normallizeSongs(list, callback) { let ret = [] let index = 1 list.forEach((item) => { let {musicData} = item // 得到music对象 if (musicData.songid && musicData.albummid) { getSongVkey(musicData.songmid).then((res) => { if (res.code === ERR_OK) { const sVkey = res.req_0.data.midurlinfo[0] const songVkey = sVkey.vkey const newSong = createSong(musicData, songVkey) console.log(newSong) ret.push(newSong) if (index === list.length) { callback && callback(ret) } index ++ } }) } }) } 方法二###(实测没有问题)这个是抓取的是h5版qq音乐的jsonp接口singer.jsexport function getSongVkey(songmid) { const url = ‘https://c.y.qq.com/base/fcgi-bin/fcg_music_express_mobile3.fcg' const data = Object.assign({}, { callback: ‘musicJsonCallback’, loginUin: 3051522991, format: ‘jsonp’, platform: ‘yqq’, needNewCode: 0, cid: 205361747, uin: 3051522991, guid: 5931742855, songmid: songmid, filename: C400${songmid}.m4a })song.jsexport function createSong(musicData, songVkey) { return new Song({ id: musicData.songid, mid: musicData.songmid, singer: filterSinger(musicData.singer), name: musicData.songname, album: musicData.albumname, duration: musicData.interval, image: https://y.gtimg.cn/music/photo_new/T002R300x300M000${musicData.albummid}.jpg?max_age=2592000, url: http://dl.stream.qqmusic.qq.com/C400${musicData.songmid}.m4a?fromtag=38&amp;guid=5931742855&amp;vkey=${songVkey} })}singer-detail_normallizeSongs(list) { let ret = [] list.forEach((item) => { let {musicData} = item // 得到music对象 getSongVkey(musicData.songmid).then((res) => { const songVkey = res.data.items[0].vkey if (musicData.songid && musicData.albummid) { ret.push(createSong(musicData, songVkey)) } }) }) console.log(ret) return ret } ...

March 25, 2019 · 2 min · jiezi

想知道jsonp到底是怎么实现的?看我,包教会!

不管你好不好,反正我是番茄酱。为啥要写这篇文章呢,因为我想写。看这个文章的你肯定是想学会jsonp吧(废话),那遇到这个文章是你的福气。我敢保证这是全网最容易看懂的文章。当然,你如果不会写js,不懂什么叫跨域,那就算了。别勉强了,勉强是没有幸福的(而且你也没有学习jsonp实现方法的必要)。首先声明,这篇文章不涉及后台代码的具体实现,关于后台的部分只说思路。好啦,那我们开课啦!总的实现思路我这篇教程的结构是总-分-总(瞎扯的,实际上是总-随意-随意-…-随意)。我们先来说说总的实现思路。我们都知道由于“同源策略”(不懂啥是同源策略没关系,反正你知道有跨域现象就行了),而导致我们跨域的ajax请求发送失败,浏览器报错。但是呢script标签的src是没有跨域一说的,也就是说你可以随便引用别的网站的js。这就是总的实现思路。如果不理解这一点,也不用往下看了,因为你以你的知识储备和理解能力不合适看这文章。说完总的实现思路,我们来看具体怎么做吧。1:先忘记我们要实现jsonp先忘了我们的目标,看一下我们需要完成jsonp而需要掌握的知识。先理解了这些,才能理解jsonp的实现。1.1:基础的js代码我们在页面写个这样的代码:<script> function a() { console.log(‘hello cat!’); }</script><script> a();</script>运行结果:对于代码和结果没有异议吧。为啥我要写这样的函数。我要说明的是这样一点:后一个script标签里的代码可以引用前一个script代码里的函数(全局)。老规矩,理解了这点就继续往下看。1.2:script标签引用文本我们在html里写这样的代码:<script> function a() { console.log(‘hello cat2!’); }</script>然后我们在同路径下新建一个a.txt。并且a.txt里的文本如下:a();然后我们在html里引用a.txt。完整的代码如下:<script> function a() { console.log(‘hello cat2!’); }</script><script src=“a.txt”></script>刷新页面,控制台如下:也就是说txt里的代码被执行了。所以a函数才会被执行。我要说明的是:scritpt标签引用的外部文件中的文本内容会被当成js来解析。也就是说相当于是这样的代码:<script> function a() { console.log(‘hello cat2!’); }</script><script> a();</script>1.3:后台返回文本如果我们的后台给我们返回的不是数据,而是跟a.txt一样的文本如下文本:a();如我们请求地址为:https://www.a.com/a。则我们此时的完整代码为:<script> function a() { console.log(‘hello cat2!’); }</script><script src=“https://www.a.com/a"></script>那可以预见,最终的结果会与1.2一致。因为也等于是如下的代码:<script> function a() { console.log(‘hello cat2!’); }</script><script> a();</script>小结以上的东西只是需要完成jsonp要懂的知识。你理解了可以继续往下看。先不要深究“这样怎么能实现”的问题。不要急,我后面会说的。如果不理解上面的知识可以多看几遍。能够自己动手实验最好。2:再看看一般的ajax请求我们一般的ajax请求,是后台给我们一个请求地址,我们发送请求,然后后台返回给我们json格式的信息。例如我们要请求的地址是:https://www.a.com/userInfo (获取用户信息)后台应该返回给我们的数据是:{ “name”: “番茄酱”, “wechat”: “fan_qie_jiang666”, “qq”: “1164431166”, “email”: “1164431166@qq.com”}也就是说我们最终需要的是服务器把json格式的数据给我们。但是我们用1里说的方法,虽然服务器能调用我们本地的函数,但是我们怎么能获取到数据呢?那这样,我们把1.3的html代码改成这样:<script> function a(res) { console.log(res); }</script><script src=“https://www.a.com/userInfo"></script>服务器返回的文本改成这样:a({ “name”: “番茄酱”, “wechat”: “fan_qie_jiang666”, “qq”: “1164431166”, “email”: “1164431166@qq.com”});也就是相当于这样的代码:<script> function a(res) { console.log(res); }</script><script> a({ “name”: “番茄酱”, “wechat”: “fan_qie_jiang666”, “qq”: “1164431166”, “email”: “1164431166@qq.com” });</script>最终结果:也就是说我们获取到了我们需要的数据。但是万一我们的function不叫a,或者原本叫a,但是因为种种原因需要改名,这样后台也要跟着改代码。这增加了沟通成本,也增加了后台的工作量。并且可能每个接口你们都需要去沟通这个函数的名字。这是问题呀!3.解决函数名的问题用script标签里的src相当于向服务器发送了get请求。不管你理不理解上面这点,记住就行了。既然是相当于get请求,那就可以带参。并且后台也能获得这个参数的值。既然这样那我们是不是跟后台沟通好我们给所有用jsonp的请求弄个参数,这个参数的值是我们本地的函数名。后台直接给我们返回函数名然后参数为数据值就ok辣?不理解的话看下面的过程。比如我们和后台沟通好参数名叫balabala,那代码就像下面这样:<script> function xiaoMoXian(res) { console.log(res); }</script><script src=“https://www.a.com/userInfo?balabala=xiaoMoXian"></script>后台收到了这个请求,不再像之前那样直接返回给我们a(…)。因为我们已经说好了,函数名不再是固定的a,而是balabala这个参数的值才是我们的函数名。于是后台去获取balabala这个参数的值,获取到的是xiaoMoXian。于是后台返回给我们:xiaoMoXian({ “name”: “番茄酱”, “wechat”: “fan_qie_jiang666”, “qq”: “1164431166”, “email”: “1164431166@qq.com”});于是代码就相当于是:<script> function xiaoMoXian(res) { console.log(res); }</script><script> xiaoMoXian({ “name”: “番茄酱”, “wechat”: “fan_qie_jiang666”, “qq”: “1164431166”, “email”: “1164431166@qq.com” });</script>最终结果与2相同。小结以上就是jsonp的实现过程。我们已经完成了不用ajax来请求,而利用script标签src属性的跨域特性,来实现我们获取数据的目的。我来小结下我们用到的知识点:ajax请求受同源策略的影响不能跨域。(问题)script标签的src是可以跨域的,不受同源策略的影响。(总的方法)后一个script标签里的代码可以引用前一个script代码里的函数。scritpt标签引用的外部文件中的文本内容会被当成js来解析。(结合3可以获取数据)用script标签里的src相当于向服务器发送了get请求。(解决函数名的问题)看到这并且看懂就说明你已经差不多可以毕业了。因为你已经完全懂了jsonp怎么实现的。可是我们一般用jsonp好像没这么麻烦呀,也不用专门去写个函数来给后台调用,也不用去写script标签写src到我们的请求地址,也不用沟通什么参数名。哪像你说的这么麻烦!?哈哈,我要加班啦。预知后事如何,请多点赞。赞够多我就更。或者加我微信给我发1块钱红包,众筹到10元我就更(谁还没个身价了 ̄へ ̄)。 ...

March 11, 2019 · 1 min · jiezi

原生js实现Ajax,JSONP

Ajax内部的几个执行步骤创建XMLHttpRequest对象(new XMLHttpRequest())设置请求头(setRequestHeader)连接服务器(open())设置回调(onreadyStateChange)发送数据(send())在回调函数中获取数据JSONP利用script标签可以跨域请求资源解决跨域问题。详细解释可以看彻底弄懂跨域问题前端代码/** 原生js实现Ajax* */function Ajax(params) { params = params || {}; params.data = params.data || {}; var _json = params.jsonp ? jsonp(params): json(params); // 判断是json还是jsonp function json(params) { // 普通请求 params.type = (params.type || ‘GET’).toUpperCase(); // 设置请求默认类型 var urlData = formatParams(params.data); // 对数据进行格式化 var xhr = null; // 对xhr进行初始化 if (window.XMLHttpRequest) { xhr = new window.XMLHttpRequest(); } else { xhr = new ActiveXObject(‘Microsoft.XMLHTTP’); } var headers = params.headers || {}; if (params.type === ‘GET’) { xhr.open(params.type, params.url + ‘?’ + urlData, true); setHeaders(xhr, headers); xhr.send(null); } else { xhr.open(params.type, params.url, true); setHeaders(xhr, headers); xhr.send(JSON.stringify(params.data)); } xhr.onreadystatechange = function () { if (xhr.readyState === 4) { var status = xhr.status; if (status >= 200 && status < 300) { var response = ‘’; var type = xhr.getResponseHeader(‘Content-Type’); if (type.indexOf(‘xml’) !== -1 && xhr.responseXML) { // xml格式 response = xhr.responseXML; } else if (type.indexOf(‘application/json’) !== -1) { // JSON格式 response = JSON.parse(xhr.responseText); } else { response = xhr.responseText; // 字符串格式 } params.success && params.success(response); } else { params.error && params.error(status); } } } } function jsonp(params) { var callbackName = params.jsonp; // 回调函数名 var head = document.getElementsByTagName(‘head’)[0]; params.data[‘callback’] = callbackName; var data = formatParams(params.data); var script = document.createElement(‘script’); head.appendChild(script); // 创建jsonp函数,成功后自动让success函数调用,在自动删除 window[callbackName] = function (json) { // 设置回调,获取后台数据后才执行 head.removeChild(script); clearTimeout(script.timer); window[callbackName] = null; params.success && params.success(json); }; script.src = params.url + ‘?’ + data; // 设置src的时候才开始向后台请求数据 if (params.time) { // 限定时间 script.timer = setTimeout(function () { window[callbackName] = null; head.removeChild(script); params.error && params.error({ message: ‘超时’ }) }, params.time) } } function formatParams(data) { // 使用 encodeURIComponent 对 URI的某部分编码 var arr = []; for (var key in data) { arr.push(encodeURIComponent(key) + ‘=’ + encodeURIComponent(data[key])); } // 添加随机数,防止缓存 arr.push(‘v=’ + random()); return arr.join(’&’); } function random() { return Math.floor(Math.random() * 10000 + 500); } function setHeaders(xhr, headers) { for (var key in headers) { xhr.setRequestHeader(key, headers[key]); } }}使用方法不用jsonp请求 Ajax({ url: ‘后端接口’, type: ‘POST’, headers: { ‘Content-Type’: ‘application/json’, token: ‘xxx’ }, success(res) { console.log(res); }, error(status) { console.log(some error status = ${status}); }})jsonp请求 Ajax({ url: ‘http://localhost:8080’, headers: { ‘Content-Type’: ‘application/json’ }, jsonp: ‘getUser’, time: 2000, success(res) { console.log(res); }, error(status) { console.log(some error status = ${status.msg}); }})jsonp后台配置代码var querystring = require(‘querystring’);var http = require(‘http’);var server = http.createServer();server.on(‘request’, function(req, res) { var params = querystring.parse(req.url.split(’?’)[1]); var fn = params.callback; // jsonp返回设置 res.writeHead(200, { ‘Content-Type’: ’text/javascript’ }); var data = { user: ‘xbc’, password: ‘123456’ } res.write(fn + ‘(’ + JSON.stringify(data) + ‘)’); res.end();});server.listen(‘8080’);console.log(‘Server is running at port 8080…’);参考文章原生 JavaScript 实现 AJAX、JSONPajax 快速入门 ...

February 22, 2019 · 2 min · jiezi

九种跨域方式实现原理

前言前后端数据交互经常会碰到请求跨域,什么是跨域,以及有哪几种跨域方式,这是本文要探讨的内容。一、什么是跨域?1.什么是同源策略及其限制内容?同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个ip地址,也非同源。 同源策略限制内容有:Cookie、LocalStorage、IndexedDB 等存储性内容DOM 节点AJAX 请求发送后,结果被浏览器拦截了但是有三个标签是允许跨域加载资源<img src=XXX><link href=XXX><script src=XXX>2.常见跨域场景当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。常见跨域场景如下图所示: 特别说明两点:第一:如果是协议和端口造成的跨域问题“前台”是无能为力的。第二:在跨域问题上,仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”。这里你或许有个疑问:请求跨域了,那么请求到底发出去没有?跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。二、跨域解决方案1.jsonp1) JSONP原理利用<script> 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。2) JSONP和AJAX对比JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)3) JSONP优缺点JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。4) JSONP的实现流程声明一个回调函数,其函数名(如show)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data)。创建一个<script>标签,把那个跨域的API数据接口地址,赋值给script的src,还要在这个地址中向服务器传递该函数名(可以通过问号传参:?callback=show)。服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是show,它准备好的数据是show(‘我不爱你’)。最后服务器把准备的数据通过HTTP协议返回给客户端,客户端再调用执行之前声明的回调函数(show),对返回的数据进行操作。在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就需要自己封装一个 JSONP函数。// index.htmlfunction jsonp({ url, params, callback }) { return new Promise((resolve, reject) => { let script = document.createElement(‘script’) window[callback] = function(data) { resolve(data) document.body.removeChild(script) } params = { …params, callback } // wd=b&callback=show let arrs = [] for (let key in params) { arrs.push(${key}=${params[key]}) } script.src = ${url}?${arrs.join('&amp;')} document.body.appendChild(script) })}jsonp({ url: ‘http://localhost:3000/say’, params: { wd: ‘Iloveyou’ }, callback: ‘show’}).then(data => { console.log(data)})上面这段代码相当于向http://localhost:3000/say?wd=Iloveyou&callback=show这个地址请求数据,然后后台返回show(‘我不爱你’),最后会运行show()这个函数,打印出’我不爱你’// server.jslet express = require(’express’)let app = express()app.get(’/say’, function(req, res) { let { wd, callback } = req.query console.log(wd) // Iloveyou console.log(callback) // show res.end(${callback}('我不爱你'))})app.listen(3000)5) jQuery的jsonp形式JSONP都是GET和异步请求的,不存在其他的请求方式和同步请求,且jQuery默认就会给JSONP的请求清除缓存。$.ajax({url:“http://crossdomain.com/jsonServerResponse",dataType:"jsonp",type:"get",//可以省略jsonpCallback:“show”,//->自定义传递给服务器的函数名,而不是使用jQuery自动生成的,可省略jsonp:“callback”,//->把传递函数名的那个形参callback,可省略success:function (data){console.log(data);}});2.corsCORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求和复杂请求。1) 简单请求只要同时满足以下两大条件,就属于简单请求条件1:使用下列方法之一:GETHEADPOST条件2:Content-Type 的值仅限于下列三者之一:text/plainmultipart/form-dataapplication/x-www-form-urlencoded请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。2) 复杂请求不符合以上条件的请求就肯定是复杂请求了。 复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。我们用PUT向后台请求时,属于复杂请求,后台需做如下配置:// 允许哪个方法访问我res.setHeader(‘Access-Control-Allow-Methods’, ‘PUT’)// 预检的存活时间res.setHeader(‘Access-Control-Max-Age’, 6)// OPTIONS请求不做任何处理if (req.method === ‘OPTIONS’) { res.end() }// 定义后台返回的内容app.put(’/getData’, function(req, res) { console.log(req.headers) res.end(‘我不爱你’)})接下来我们看下一个完整复杂请求的例子,并且介绍下CORS请求相关的字段// index.htmllet xhr = new XMLHttpRequest()document.cookie = ’name=xiamen’ // cookie不能跨域xhr.withCredentials = true // 前端设置是否带cookiexhr.open(‘PUT’, ‘http://localhost:4000/getData’, true)xhr.setRequestHeader(’name’, ‘xiamen’)xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) { console.log(xhr.response) //得到响应头,后台需设置Access-Control-Expose-Headers console.log(xhr.getResponseHeader(’name’)) } }}xhr.send()//server1.jslet express = require(’express’);let app = express();app.use(express.static(__dirname));app.listen(3000);//server2.jslet express = require(’express’)let app = express()let whitList = [‘http://localhost:3000’] //设置白名单app.use(function(req, res, next) { let origin = req.headers.origin if (whitList.includes(origin)) { // 设置哪个源可以访问我 res.setHeader(‘Access-Control-Allow-Origin’, origin) // 允许携带哪个头访问我 res.setHeader(‘Access-Control-Allow-Headers’, ’name’) // 允许哪个方法访问我 res.setHeader(‘Access-Control-Allow-Methods’, ‘PUT’) // 允许携带cookie res.setHeader(‘Access-Control-Allow-Credentials’, true) // 预检的存活时间 res.setHeader(‘Access-Control-Max-Age’, 6) // 允许返回的头 res.setHeader(‘Access-Control-Expose-Headers’, ’name’) if (req.method === ‘OPTIONS’) { res.end() // OPTIONS请求不做任何处理 } } next()})app.put(’/getData’, function(req, res) { console.log(req.headers) res.setHeader(’name’, ‘jw’) //返回一个响应头,后台需设置 res.end(‘我不爱你’)})app.get(’/getData’, function(req, res) { console.log(req.headers) res.end(‘我不爱你’)})app.use(express.static(__dirname))app.listen(4000)上述代码由http://localhost:3000/index.html向http://localhost:4000/跨域请求,正如我们上面所说的,后端是实现 CORS 通信的关键。3.postMessagepostMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:页面和其打开的新窗口的数据传递多窗口之间消息传递页面与嵌套的iframe消息传递上面三个场景的跨域数据传递postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。otherWindow.postMessage(message, targetOrigin, [transfer]);message: 将要发送到其他 window的数据。targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串””(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。transfer(可选):是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。接下来我们看个例子: http://localhost:3000/a.html页面向http://localhost:4000/b.html传递“我爱你”,然后后者传回”我不爱你”。// a.html <iframe src=“http://localhost:4000/b.html” frameborder=“0” id=“frame” onload=“load()"></iframe> //等它加载完触发一个事件 //内嵌在http://localhost:3000/a.html <script> function load() { let frame = document.getElementById(‘frame’) frame.contentWindow.postMessage(‘我爱你’, ‘http://localhost:4000’) //发送数据 window.onmessage = function(e) { //接受返回数据 console.log(e.data) //我不爱你 } } </script>// b.html window.onmessage = function(e) { console.log(e.data) //我爱你 e.source.postMessage(‘我不爱你’, e.origin) }4.websocketWebsocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。我们先来看个例子:本地文件socket.html向localhost:3000发生数据和接受数据// socket.html<script> let socket = new WebSocket(‘ws://localhost:3000’); socket.onopen = function () { socket.send(‘我爱你’);//向服务器发送数据 } socket.onmessage = function (e) { console.log(e.data);//接收服务器返回的数据 }</script>// server.jslet express = require(’express’);let app = express();let WebSocket = require(‘ws’);//记得安装wslet wss = new WebSocket.Server({port:3000});wss.on(‘connection’,function(ws) { ws.on(‘message’, function (data) { console.log(data); ws.send(‘我不爱你’) });})5. Node中间件代理(两次跨域)实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。 代理服务器,需要做以下几个步骤:接受客户端请求 。将请求 转发给服务器。拿到服务器 响应 数据。将 响应 转发给客户端。 我们先来看个例子:本地文件index.html文件,通过代理服务器http://localhost:3000向目标服务器http://localhost:4000请求数据。// index.html(http://127.0.0.1:5500) <script src=“https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script> $.ajax({ url: ‘http://localhost:3000’, type: ‘post’, data: { name: ‘xiamen’, password: ‘123456’ }, contentType: ‘application/json;charset=utf-8’, success: function(result) { console.log(result) // {“title”:“fontend”,“password”:“123456”} }, error: function(msg) { console.log(msg) } }) </script> // server1.js 代理服务器(http://localhost:3000)const http = require(‘http’)// 第一步:接受客户端请求const server = http.createServer((request, response) => { // 代理服务器,直接和浏览器直接交互,需要设置CORS 的首部字段 response.writeHead(200, { ‘Access-Control-Allow-Origin’: ‘’, ‘Access-Control-Allow-Methods’: ‘’, ‘Access-Control-Allow-Headers’: ‘Content-Type’ }) // 第二步:将请求转发给服务器 const proxyRequest = http .request( { host: ‘127.0.0.1’, port: 4000, url: ‘/’, method: request.method, headers: request.headers }, serverResponse => { // 第三步:收到服务器的响应 var body = ’’ serverResponse.on(‘data’, chunk => { body += chunk }) serverResponse.on(’end’, () => { console.log(‘The data is ’ + body) // 第四步:将响应结果转发给浏览器 response.end(body) }) } ) .end()})server.listen(3000, () => { console.log(‘The proxyServer is running at http://localhost:3000’)})// server2.js(http://localhost:4000)const http = require(‘http’)const data = { title: ‘fontend’, password: ‘123456’ }const server = http.createServer((request, response) => { if (request.url === ‘/’) { response.end(JSON.stringify(data)) }})server.listen(4000, () => { console.log(‘The server is running at http://localhost:4000’)})上述代码经过两次跨域,值得注意的是浏览器向代理服务器发送请求,也遵循同源策略,最后在index.html文件打印出{“title”:“fontend”,“password”:“123456”}6.nginx反向代理实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。先下载nginx,然后将nginx目录下的nginx.conf修改如下:// proxy服务器server { listen 80; server_name www.domain1.com; location / { proxy_pass http://www.domain2.com:8080; #反向代理 proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名 index index.html index.htm; # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用 add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为 add_header Access-Control-Allow-Credentials true; }}最后通过命令行nginx -s reload启动nginx// index.htmlvar xhr = new XMLHttpRequest();// 前端开关:浏览器是否读写cookiexhr.withCredentials = true;// 访问nginx中的代理服务器xhr.open(‘get’, ‘http://www.domain1.com:81/?user=admin', true);xhr.send();// server.jsvar http = require(‘http’);var server = http.createServer();var qs = require(‘querystring’);server.on(‘request’, function(req, res) { var params = qs.parse(req.url.substring(2)); // 向前台写cookie res.writeHead(200, { ‘Set-Cookie’: ’l=a123456;Path=/;Domain=www.domain2.com;HttpOnly’ // HttpOnly:脚本无法读取 }); res.write(JSON.stringify(params)); res.end();});server.listen(‘8080’);console.log(‘Server is running at port 8080…’);7.window.name + iframewindow.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。其中a.html和b.html是同域的,都是http://localhost:3000;而c.html是http://localhost:4000 // a.html(http://localhost:3000/b.html) <iframe src=“http://localhost:4000/c.html” frameborder=“0” onload=“load()” id=“iframe”></iframe> <script> let first = true // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name function load() { if(first){ // 第1次onload(跨域页)成功后,切换到同域代理页面 let iframe = document.getElementById(‘iframe’); iframe.src = ‘http://localhost:3000/b.html’; first = false; }else{ // 第2次onload(同域b.html页)成功后,读取同域window.name中数据 console.log(iframe.contentWindow.name); } } </script>b.html为中间代理页,与a.html同域,内容为空。 // c.html(http://localhost:4000/c.html) <script> window.name = ‘我不爱你’ </script>总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。8.location.hash + iframe实现原理: a.html欲与c.html跨域相互通信,通过中间页b.html来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。具体实现步骤:一开始a.html给c.html传一个hash值,然后c.html收到hash值后,再把hash值传递给b.html,最后b.html将结果放到a.html的hash值中。 同样的,a.html和b.html是同域的,都是http://localhost:3000;而c.html是http://localhost:4000 // a.html <iframe src=“http://localhost:4000/c.html#iloveyou”></iframe> <script> window.onhashchange = function () { //检测hash的变化 console.log(location.hash); } </script> // b.html <script> window.parent.parent.location.hash = location.hash //b.html将结果放到a.html的hash值中,b.html可通过parent.parent访问a.html页面 </script> // c.html console.log(location.hash); let iframe = document.createElement(‘iframe’); iframe.src = ‘http://localhost:3000/b.html#idontloveyou’; document.body.appendChild(iframe);9.document.domain + iframe该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。 只需要给页面添加 document.domain =‘test.com’ 表示二级域名都相同就可以实现跨域。实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。我们看个例子:页面a.zf1.cn:3000/a.html获取页面b.zf1.cn:3000/b.html中a的值// a.html<body> helloa <iframe src=“http://b.zf1.cn:3000/b.html" frameborder=“0” onload=“load()” id=“frame”></iframe> <script> document.domain = ‘zf1.cn’ function load() { console.log(frame.contentWindow.a); } </script></body> // b.html<body> hellob <script> document.domain = ‘zf1.cn’ var a = 100; </script></body>三、总结CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案JSONP只支持GET请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。不管是Node中间件代理还是nginx反向代理,主要是通过同源策略对服务器不加限制。日常工作中,用得比较多的跨域方案是cors和nginx反向代理 ...

February 12, 2019 · 4 min · jiezi

一分钟了解 JSONP

为什么要写这个短文?我在复习 JSONP 知识的时候,随便搜了几篇文章看,额……后来就有了写它的想法。首先,页面中的<script>标签里面放的是 js 代码,而加上 src 属性后<script>标签就有了加载和运行外部 js 代码的能力。于是,不法分子们就抓住这个漏洞,开始了与浏览器的同源策略做斗争,打了场胜仗。加上 src 属性的 script 标签,是利用 HTTP 的 GET 方法去访问你指定的 url 的,它预期会 GET 到一个 js 文件或者是一段 js 代码,然后浏览器会去执行它。于是呢,所谓的 JSONP 就相当于是利用 GET 到的这一段 js 代码的方式。使用方法就是:1、前后端相互沟通好,前端定义好一个函数,用来解析异步请求的数据。例子:function ajax(result) { // 处理 result}2、后端写一个接口,告诉前端你请求我接口的时候要加上 function 这个参数,然后返回这个函数的执行方式。例子:// 接口:http://www.abc.com/api?function=ajax// 后端得到 function 参数的这个前端定义的函数名,示例是 ajax,然后像下面这样组合好后返回:// return ‘ajax(1)’;3、前端在 script 标签里的 src 属性设置为这个接口。例子:<script src=“http://www.abc.com/api?function=ajax">这个时候,浏览器就会去 GET 请求接口,然后 script 标签得到 ajax(1) 这个 js 代码,然后浏览器开始执行它,因为你事先已经定义过 ajax 函数了,所以 ajax(1) 会正常运行。但是,第三步需要是异步请求,那么就在需要做请求操作的地方,利用 js 生成这段 script 标签放到 <head> 里面就行了(或者是把 src 用js动态改一下,这个我倒是没有试过)。这就是 JSONP 啦。 ...

January 24, 2019 · 1 min · jiezi

跨域

前端跨域的各种知识点每次复习基础知识的时候,都会看一些有关跨域的知识点。但在工作中从来没有用到过。恰巧,前几天官网的同事让我请求他们的接口,并指明需要用到jsonp。说实话,当时我是有一点懵的。(内心os:jsonp到底应该咋用啊)。为了下次再遇到这种情况不至于很尴尬。今天,就来总结一下跨域的基本知识点。1.为什么会发生跨域这种情况呢?我们通常都是用ajax进行网络请求的。ajax的技术核心是XMLHttpRequest对象(简称XHR对象)。(既然都提到ajax了,不如复习下吧)1.1 XHR的用法1.1.1 同步请求var xhr = createXHR()xhr.open(‘get’, ’example.php’, false) // 参数:请求方式、请求地址、是否异步xhr.send(null)if((xhr.status > 200 && xhr.status < 300) || xhr.status == 304) { alert(xhr.responseText)} else { alert(’error’)}open()方法并不会真正的发送请求。而知识启动一个请求以备发送。send()方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null。调用send()方法之后,请求就会被分派到服务器。在收到响应后,响应会自动填充XHR对象的属性。responseText:响应的主体被返回的文本 responseXML: 如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保存着响应数据的XML DOM文档。 status:响应的HTTP状态。(200:请求成功。304:请求的资源没有被修改。302:重定向。404:找不到路径。500:服务器报错) statusText:HTTP状态的说明1.1.2异步请求异步请求,可以检测XHR的readyState属性。该属性表示请求/响应过程的当前活动阶段。var xhr = createXHR();xhr.onreadystatechange = function() { if(xhr.readyState === 4) { if((xhr.status > 200 && xhr.status < 300) || xhr.status == 304) { alert(xhr.responseText) } else { alert(’error’) } }}xhr.open(‘get’, ’example.php’, true)xhr.send(null)2.什么是跨域跨域:同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。同源指:协议、域名、端口号必须一致。同源策略控制了不同源之间的交互,例如在使用XMLHttpRequest 或 标签时则会受到同源策略的约束。这些交互通常分为三类:通常允许跨域写操作(Cross-origin writes)。例如链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight。通常允许跨域资源嵌入(Cross-origin embedding)。通常不允许跨域读操作(Cross-origin reads)。但常可以通过内嵌资源来巧妙的进行读取访问。例如可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法,或availability of an embedded resource。下面为允许跨域资源嵌入的示例,即一些不受同源策略影响的标签示例:<script src="…"></script>标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。<link rel=“stylesheet” href="…">标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type消息头。不同浏览器有不同的限制: IE, Firefox, Chrome, Safari 和 Opera。<img>嵌入图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG<video> 和 <audio>嵌入多媒体资源。<object>, <embed> 和 <applet>的插件。@font-face引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。<frame>和<iframe>载入的任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。3.跨域的解决方法下面是比较常用的解决跨域的方法。3.1.1 jsonpjsonp是利用动态添加script标签的形式,来进行跨域访问。因为script标签和img标签都有能力不受限制的从其他域加载资源。jsonp由两部分组成:回调函数和数据(callback({name: ‘xuying’}))如果其他域不是特别安全,如果用jsonp进行跨域,则会有一些安全隐患。其次,要确定jsonp请求是否失败也并不容易。3.1.2 CORS(跨域资源共享)跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。比如一个简单的get或者post请求,他没有自定义的头部,而主体内容应该是text/plain。在发送该请求时,需要给它附加一个额外的origin头部,其中包含请求页面的源信息(Origin: http://www.nnn.net),如果服务…,就在Access-Control-Allow-Origin头部中回发相同的源信息(如果是公共资源,可以回发’*’)(Access-Control-Allow-Origin: http://www.nnn.net)如果没有这个头部,或者有这个头部但源信息不匹配,浏览器都会驳回请求。ps:请求和响应都不包含cookie信息。其他有关跨域的知识点,可以看这两篇博客:掘金:https://juejin.im/post/5b5ff1…github:https://github.com/Nealyang/Y… ...

December 19, 2018 · 1 min · jiezi

简洁易用的基于Promise的jsonp库easy-jsonp,了解下

现在流行的axios库不支持jsonp,因此这里推荐一个jsonp库,简单易用。以下是介绍:Easy JSONPA minimal and lightweight JSONP implementation which is used to be a kind of cross domain solutions.FeaturesImplement JSONP request from the browserCombine URL query parameters by default behaviorSupport the [Promise] APILimit JSONP request periodHandle network error responseInstall# using npmnpm i easy-jsonp# using yarnyarn add easy-jsonp# using script target<script src=“jsonp.js”></script>UsageJSONP only support GET methods, same as easy-JSONP.The code below show you how to use package as a dependency// as a request dependency named jsonpimport jsonp from ’easy-jsonp’const jsonp = require(’easy-jsonp’).defaultjsonp({ url: ‘http://localhost’, // global function named callback will be invoked when JSONP response callback: ‘callback’, // any different name from request module timeout: 3000, params: { // eg. ?key0=0&key1=1… key0: 0, key1: 1 }}) .then(res => console.log(res)) .catch(err => console.error(err))⚠️ Notice: Parameter callback value MUST NOT be same as request module name (eg. dependency named jsonp above code), otherwise request module only works once and function named value of parameter callback will be reset to null (internal implementation) which means the same name request module will be also reset unexpectedly.For more customization capability, This package wouldn’t convert callback to a new name to prevent unexpected reset.jsonp({ // custom configuration})⚠️ Notice: For same reason, parameter callback value MUST NOT be jsonp.Parametersoptions parametertyperequireddescriptionurlStringtrueJSONP request addresstimeoutNumberfalse, default : 6000 millisecondshow long after timeout error is emitted. 0 to disablecallbackStringfalse, default : ‘jsonpCallback’+Date.now()global callback function name which is used to handle JSONP response.paramsObjectfalse, default: {}other parameters in query string parametersNoticeUncaught SyntaxError: Unexpected token :errorIt mostly doesn’t support JSONP request when you are calling a JSON api. The difference between JSON api and JSONP is that JSON api response with an object like { num: 1 } (It will throw a error when client executed this response as a function. ). On the other hand, JSONP will respond with a function wrapped object like callback({ num: 1 }) and we will get what we need when client executed this response as a function. ...

September 29, 2018 · 2 min · jiezi