珠峰培训

JavaScript中通过JSONP跨域请求详解

作者:周啸天

2017-01-14 22:12:41

250

JavaScript中通过JSONP跨域请求详解

前后端分离项目,前端需要从服务器端获取数据,然后做数据的绑定以及其它的数据交互

  • AJAX:在同源请求下,使用AJAX进行操作
  • JSONP:在非同源请求下,使用JSONP进行操作

同源和非同源(跨域):

用当前页面的URL和API文档中请求数据的URL进行对比,如果协议、域名、端口号完全一致属于同源策略,只要有一个不一样就属于跨域策略

JSONP的原理

SCRIPT、LINK、IMG、IFRAME、AUDIO、VIDEO这些标签都有一个共同的特点

  • 没有同源和非同源的限制,只要放在SRC或者HREF中引入进来,都可以向指定的地址发送请求,获取到需要的数据

前端任务

1、创建一个方法

function fn(result){
console.log(result);
}

2、增加一个SCRIPT标签,把我们需要请求的数据接口地址,放到SRC中,让浏览器帮我们向指定的服务器发送请求,在这个过程中我们需要把我们的方法,通过问号传参的方式传递给服务器

<script src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=z&cb=fn"></script>

上述代码中的 &cb=fn ,其中cb是一个标识(一般服务器端定义的标识是callback,但是这个可以自己随便定义,百度这边定义的就是cb);而传递的值fn就是我们自己定义的方法名字;

服务器端任务

1、接收客户端请求的URL,然后把URL问号传递的参数值进行解析

wd : z
cb : fn

2、根据传递进来的wd参数的值,到数据库中获取到和关键词匹配的数据

{q:"珠峰培训",p:false,s:["北京珠峰培训","珠峰培训node.js","珠峰培训js","珠峰培训怎么样","珠峰培训css","珠峰培训视频","珠峰培训中","珠峰培训 vue","珠峰培训 下载","珠峰培训vip"]}

3、把获取的结果返回给客户端,注意的是:服务器返回的结果是一个字符串 ‘函数名(数据内容)’

 fn({q:"珠峰培训",p:false,s:["北京珠峰培训","珠峰培训node.js"...]});

4、客户端接收到返回的值之后,把之前定义的fn方法执行,数据就是给形参result传递的参数值,这样我们就获取到所需要的数据了

下面是详细的描述图:

Alt text

使用JSONP完成百度搜索

Alt text
HTML结构
<section class="search">
<input type="search" id="searchInp" autofocus/>
<ul class="searchItem">
<!--<li>珠峰培训</li>
<li>珠峰培训怎么样</li>-->

</ul>
</section>
CSS样式
<style>
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}


.search {
margin: 20px auto;
width: 300px;
}


.search input {
display: block;
padding: 0 5px;
width: 300px; /*TYPE=SEARCH 导致当前的文本框的盒子模型是BORDER-BOX,我们设定的WIDTH是盒子的总宽度,不会受到PADDING和BORDER的影响*/
height: 30px;
line-height: 30px;
border: 1px solid green;
font-size: 12px;
}


.search .searchItem {
display: none;
border: 1px solid green;
border-top: none;
}


.search .searchItem li {
padding: 0 5px;
line-height: 30px;
font-size: 12px;
cursor: pointer;
}


.search .searchItem li:hover {
background: #EEE;
}

</style>
JavaScript处理逻辑

首先需要导入jQuery

<script>
var $searchInp = $('#searchInp'),
$searchItem = $('.searchItem');

var searchRender = (function () {
function fn(result) {
if (result) {
result = result['s'];

//->返回的数据没有匹配到模糊信息,我们让UL隐藏即可
if (result.length === 0) {
$searchItem.html('').css('display', 'none');
return;
}

//->如果有匹配的信息我们就展示在页面中
var str = '';
$.each(result, function (index, item) {
str += '<li>' + item + '</li>';
});
$searchItem.html(str).css('display', 'block');
}
}

return {fn: fn}
})();

$searchInp.on('keyup focus', function (e) {
if (/^(37|38|39|40|13)$/.test(e.keyCode)) return;
var val = $(this).val();
$.ajax({
url: 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=' + val,
type: 'get',
dataType: 'jsonp',
jsonp: 'cb',
jsonpCallback: 'searchRender.fn'//->FN需要是全局函数,为了防止全局污染我们可以把函数放在一个模块下(单例模式解决)
});
});

$('body').on('click', function (e) {
var tar = e.target,
tarTag = tar.tagName,
$tar = $(tar);
//->LI
if (tarTag === 'LI' && $tar.parent().hasClass('searchItem')) {
$searchInp.val($tar.html());
$searchItem.css('display', 'none');
return;
}

//->INPUT
if (tarTag === 'INPUT' && tar.id === 'searchInp') {
return;
}

//->OTHERS
$searchItem.css('display', 'none');
});
</script>

以上案例大家还可以在原来的基础上继续完善,期待更好的作品出现哦…