相信大多数前端开发者在需要与后端进行数据交互时,为了方便快捷,都会选择<code>JQuery</code>中封装的<code>AJAX</code>方法,但是有些时候,我们只需要<code>JQuery</code>的<code>AJAX</code>请求方法,而其他的功能用到的很少,这显然是没必要的。
其实,原生<code>JavaScript</code>实现<code>AJAX</code>并不难,这篇文章将会讲解如何实现简单的<code>AJAX</code>,还有跨域请求<code>JSONP</code>!
一、AJAX
AJAX的核心是<code>XMLHttpRequest</code>。
一个完整的<code>AJAX</code>请求一般包括以下步骤:
实例化<code>XMLHttpRequest</code>对象
连接服务器
发送请求
接收响应数据
我将<code>AJAX</code>请求封装成<code>ajax()</code>方法,它接受一个配置对象<code>params</code>。
在上面的代码中,已经添加具体的注释,如需了解更多<code>AJAX</code>,可查看博主的书籍《 JavaScript半知半解》中的 <code>AJAX</code>章节:AJAX
使用实例:
二、JSONP
同源策略
AJAX之所以需要“跨域”,罪魁祸首就是浏览器的 <code>同源策略</code>。即,一个页面的AJAX只能获取这个页面相同源或者相同域的数据。 如何叫“同源”或者“同域”呢?——<code>协议、域名、端口号都必须相同</code>。例如:
当跨域请求时,一般都会看到这个错误: <code>XMLHttpRequest cannot load http://ghmagical.com/article/?intro=jsonp%E8%AF%B7%E6%B1%82&v=5520. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.</code>
那如何跨域请求呢?这时,JSONP就登场了!
JSONP(JSON with Padding) 是一种跨域请求方式。主要原理是利用了<code>script </code>标签可以跨域请求的特性,由其 <code>src</code> 属性发送请求到服务器,服务器返回 <code>JavaScript </code>代码,浏览器接受响应,然后就直接执行了,这和通过 <code>script</code> 标签引用外部文件的原理是一样的。
JSONP由两部分组成:<code>回调函数</code>和<code>数据</code>,回调函数一般是在浏览器控制,作为参数发往服务器端(当然,你也可以固定回调函数的名字,但客户端和服务器端的名称一定要一致)。当服务器响应时,服务器端就会把该函数和数据拼成字符串返回。
JSONP的请求过程:
请求阶段:浏览器创建一个 <code>script</code> 标签,并给其<code>src</code> 赋值(类似 <code>http://example.com/api/?callback=jsonpCallback</code> )。
发送请求:当给<code>script</code>的<code>src</code>赋值时,浏览器就会发起一个请求。
数据响应:服务端将要返回的<code>数据</code>作为参数和<code>函数名称</code>拼接在一起(格式类似”<code>jsonpCallback({name: 'abc'})</code>”)返回。当浏览器接收到了响应数据,由于发起请求的是 <code>script</code>,所以相当于直接调用 <code>jsonpCallback</code> 方法,并且传入了一个参数。
对于<code>JQuery</code>的JSONP请求,这里就不多讲了,之前也写过一篇文章《JQuery的Ajax请求跨域问题》。
在这里讲解一下用原生<code>JavaScript</code>如何实现。
依旧是<code>ajax()</code>方法里添加JSONP,后面会将两者整合在一起,JSONP的配置参数主要多了一个<code>jsonp</code>参数,它就是你的回调函数名。
注意:因为 <code>script</code> 标签的<code> src</code> 属性只在第一次设置的时候起作用,导致 <code>script</code> 标签没法重用,所以每次完成操作之后要移除;
在这里后台使用PHP处理:
注意:别漏了用函数名与数据拼接返回。
当然,前面也说过,你可以给定固定回调函数名: