本文章采用倒序和插叙等进行叙述的手法,边吃西瓜边浏览效果更佳…
使用XMLHttpRequest (XHR)对象可以与服务器交互。您可以从URL获取数据,而无需让整个的页面刷新。这使得Web页面可以只更新页面的局部,而不影响用户的操作。XMLHttpRequest在 Ajax 编程中被大量使用。
Asynchronous Javascript And XML(异步JavaScript和XML),他并不是凭空出现的新技术,而是对于现有技术的结合:核心是js对象XMLHttpRequest
// 1. 创建异步对象 --相当于打开一个浏览器
var xhr = new XMLHttpRequest()
// 2. 打开与网址特定的链接 --相当于在地址栏输入访问地址
xhr.open('get','./01get.php')
// 3. 通过链接发送一次请求 --相当于在浏览器输入回车发送请求
xhr.send(null)
// 4. 指定 xhr 状态变化事件处理函数 —— 相当于处理网页呈现后的操作
xhr.onreadystatechange = function(){
// 通过 xhr 的 readyState 判断此次请求的响应是否接收完成
if (this.readyState === 4) {
// 通过 xhr 的 responseText 获取到响应的响应体
console.log(this)
}
}
如果GET需要传参数,需要接在open的url地址里面
var xhr = new XMLHttpRequest()
// open 方法的第一个参数的作用就是设置请求的 method,第二个方法是路径,建立与浏览器特定端口的链接
xhr.open('POST','./02post.php')
// 设置请求头中的 Content‐Type 为 application/x‐www‐form‐urlencoded
// 标识此次请求的请求体格式为 urlencoded 以便于服务端接收数据
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
// 需要提交到服务端的数据可以通过 send 方法的参数传递
// 格式:key1=value1&key2=value2
xhr.send('key1=value1&key2=value2')//post请求参数在这里传递,并且不需要encodeURI()转码
xhr.onreadystatechange = function(){
// 状态为4才能获取完整的响应内容
if (this.readyState === 4) {
console.log(this.responseText) //获取服务端返回的内容
}
}
open的第三个参数是布尔类型,代表是否异步请求
我们废话不多说了,直接讲讲关于get和post的封装,其实就是找它们的不同…
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest(); //标准
}else{
xhr = new ActiveXObject('Microsoft.XMLHTTP'); //ie6
}
var method = method.toUpperCase()
'key1=value1&key2=value2'
但是我们需要传递的是一个对象,而且get方式请求是在open用?
连接;post需要在send进行发送xhr.readyState == 4 && xhr.status == 200
;但是个人xhr.status不是200也是需要处理的 function ajax(url,methods,params={},fn){
var xhr = null;
var methods = methods.toUpperCase() //方便后续判断
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest(); //标准
}else{
xhr = new ActiveXObject('Microsoft.XMLHTTP'); //ie6
}
// 将参数转化为字符串用&链接的格式
var arr = [] //定义一个数组接收键值对
for(var key in params){
arr.push(`${key}=${params[key]}`)
}
var str = arr.join('&')//请求格式
if(methods=='GET'){
url += '?' + str
}
xhr.open(methods,url,true)
var data = null
if(methods=='POST'){
data = str
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
}
xhr.send(data)
xhr.onreadystatechange = function(){
if(this.readyState === 4){
if(this.status===200){
fn(this.responseText)
}
}
}
}
if($_SERVER['REQUEST_METHOD']==='GET'){
$username = $_GET['username'];
$password = $_GET['password'];
$arr = array('username' => $username, 'password'=>$password,'methods'=>'get');
echo json_encode($arr);
}else{
$username = $_POST['username'];
$password = $_POST['password'];
$arr = array('username' => $username, 'password'=>$password,'methods'=>'post');
echo json_encode($arr);
}
引入我们写好的ajax.js文件,并写好前端页面
<form>
<input type="text" name="username" id="username">
<input type="text" name="password" id="password">
<button>testbutton>
form>
点击按钮先发送get请求,再发送post请求
<script>
document.querySelector('button').onclick = function(e){
e = e || window.event
e.preventDefault && e.preventDefault()
var username = document.querySelector('#username').value
var password = document.querySelector('#password').value
ajax('./test.php','get',{username:username,password:password},function(data1){
console.log(data1)
ajax('./test.php','post',{username:username,password:password},function(data1){
console.log(data1)
})
})
}
</script>
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
function axios(url,type,params){
return new Promise(function(resolve,reject){
var xhr = null;
// var type = type.toUpperCase() //方便后续判断
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest(); //标准
}else{
xhr = new ActiveXObject('Microsoft.XMLHTTP'); //ie6
}
// 将参数转化为字符串用&链接的格式
var arr = [] //定义一个数组接收键值对
for(var key in params){
arr.push(`${key}=${params[key]}`)
}
var str = arr.join('&')//请求格式
type = type.toUpperCase()
if(type=='GET'){
url += '?' + str
}
xhr.open(type,url,true)
var data = null
if(type=='POST'){
data = str
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
}
xhr.send(data)
xhr.onreadystatechange = function(){
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
}
})
}
<script src="axios.js"></script>
<script>
document.querySelector('button').onclick = function(e){
......
axios('./test.php','get',{username:username,password:password})
.then(function(data){
console.log(data)
return axios('./test.php','post',{username:username,password:password})
})
.catch(function(err){
console.log(err)
})
.then(function(data){
console.log(data)
})
}
</script>
3. 当然我们最好在封装的时候判断格式是否是json
;是的话使用JSON.parse()
将其转换,这点大家自己加上
JSON with Padding;是一种借助
script
标签发送跨域请求的技巧
其原理就是在客户端借助 script 标签请求服务端的一个动态网页,服务端的这个动态网页返回一段带有函数调用的 JavaScript 全局函数调用的脚本,将原本需要返回给客户端的数据传递进去
比如我们的访问地址是http://localhost/test/test.html
,但是请求地址域名是不同的
axios('http://127.0.0.1/test/test.php','get',{username:username,password:password})
.then(function(data){
console.log(data)
})
http://localhost/jsonp/jsonp.html
请求的后台代码jsonp.php文件
$sData = '{"msg":"","status":"0","error_code":"0","data":"服务端测试"}';
$cbName = $_GET['callback'];
echo $cbName.'('.$sData.')';
?>
前端使用jsonp进行跨域请求
<script>
function foo(data){
console.log(data)//{msg: "", status: "0", error_code: "0", data: "服务端测试"}
console.log(typeof data)//object
}
</script>
<script src="http://127.0.0.1/jsonp/jsonp.php?callback=foo" type="text/javascript"></script>
<input type="text" id="inp">
<button id="btn">点击button>
<script type="text/javascript">
var inp = document.getElementById('inp')
var btn = document.getElementById('btn')
function hello(data){
console.log(data);
}
btn.onclick = function(){
var script = document.createElement('script');
script.src = `
http://api.jisuapi.com/weather/query?appkey=eee8cacbc1e612cd&city=${inp.value}&callback=hello`;
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
}
</script>
// jsonp的封装
function Jsonp(){
}
// 创建链接
Jsonp.prototype.ranNum = function(min,max){ //生成随机数
return parseInt(Math.random()*(max-min+1)+min)
}
Jsonp.prototype.get = function(url,data){
return new Promise((resolve,reject)=>{
var num = this.ranNum(0,100) //获取[0,100]随机数
var callBackRadom = "jsonpSuccess_" + num; //指定回调函数
window[callBackRadom] = resolve;//处理函数,这是函数名,resolve成功后的回调函数(这是声明式函数)
var script = document.createElement('script');//创建script标签
var arr = [] //用来存放我们的键值对数据
script.type = "text/javascript"
script.id = callBackRadom//给它一个id;方便我们后续用来删除它
if(data!=null){
for(var key in data){
arr.push(`${key}=${encodeURIComponent(data[key])}`)//对字符串进行编码
}
var str = arr.join('&')//转化成我们想要的格式
script.src = `${url}?${str}&callback=${callBackRadom}`;//发送请求
}else{
script.src = `${url}&callback=${callBackRadom}`;
}
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);//添加到头部
this.removeJsonp(callBackRadom) //创建后拿到数据就删除
})
}
Jsonp.prototype.removeJsonp = function(id){
var head = document.getElementsByTagName('head')[0];
var el = document.getElementById(id);
if (head != null && el != null) {
head.removeChild(el);
}
}
var jsonp = new Jsonp()
<script src='jsonp.js'></script>
<script>
jsonp.get(`http://api.jisuapi.com/weather/query`,{appkey:'eee8cacbc1e612cd',city:'深圳'})
.then(data=>{
console.log(data)
return jsonp.get(`http://api.jisuapi.com/weather/query`,{appkey:'eee8cacbc1e612cd',city:'汕头'})
})
.then(data=>{
console.log(data)
})
</script>
readyState | 状态描述 | 说明 |
---|---|---|
0 | UNSENT | 代理(XHR)被创建,但尚未调用 open() 方法。 |
1 | OPENED | open() 方法已经被调用,建立了连接。 |
2 | HEADERS_RECEIVED | send() 方法已经被调用,并且已经可以获取状态行和响应头。 |
3 | LOADING | 响应体下载中, responseText 属性可能已经包含部分数据。 |
4 | DONE | 响应体下载完成,可以直接使用 responseText 。 |
由于 readystatechange 事件是在 xhr 对象状态变化时触发(不单是在得到响应时),也就意味着这个事件会被触发多次,所以我们为什么要设定xhr.readyState=4的原因
本质上 XMLHttpRequest 就是 JavaScript 在 Web 平台中发送 HTTP 请求的手段,所以我们发送出去的请求任然是HTTP 请求,同样符合 HTTP 约定的格式:
// 设置请求报文的请求行
xhr.open('GET', './time.php')
// 设置请求头
xhr.setRequestHeader('Accept', 'text/plain')
// 设置请求体
xhr.send(null)
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
// 获取响应状态码
console.log(this.status)
// 获取响应状态描述
console.log(this.statusText)
// 获取响应头信息
console.log(this.getResponseHeader('Content‐Type')) // 指定响应头
console.log(this.getAllResponseHeader()) // 全部响应头
// 获取响应体
console.log(this.responseText) // 文本形式
console.log(this.responseXML) // XML 形式,了解即可不用了
}
}
同源策略是浏览器的一种安全策略,所谓同源是指域名,协议,端口完全相同,只有同源的地址才可以相互通过AJAX 的方式请求。同源或者不同源说的是两个地址之间的关系,不同源地址之间请求我们称之为跨域请求。
由于同源从略的限制,XMLHttpRequest只允许请求前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后再服务端输出JSON数据并执行回调函数,从而解决跨域数据请求; 而JSONP 需要服务端配合,服务端按照客户端的要求返回一段 JavaScript 调用客户端的函数。
header('Access‐Control‐Allow‐Origin: *');
这种方案无需客户端作出任何变化(客户端不用改代码),只是在被请求的服务端响应的时候添加一个 AccessControl-Allow-Origin 的响应头,表示这个资源是否允许指定域请求
想象一下:在一片蓝色的天空和碧绿的湖水包围下;你在刷着微博;当你看完了内容;点击加载更多按钮;页面重新刷新了…但实际情况是:我们在访问新浪微博时,当你看到一大半了,会自动帮我们加载更多的微博,同时页面并没有刷新
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中
import Axios from 'axios'
Vue.prototype.HOST = 'http://localhost:3000'//虚拟接口
Vue.prototype.$axios = Axios//在vue中使用
// 添加请求拦截器
Axios.interceptors.request.use(function (config) {
const token = localStorage.getItem('auth_token')
config.headers['X-Access-Token'] = token
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
Axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
这是angular的
import { HttpClient } from '@angular/common/http'
...
constructor(
private http: HttpClient,
private router: Router
) { }
......
this.http.post(url, params)
.toPromise()
.then(data => {
})
.catch(err => {
})
这是vue提供的;但是已经不再维护了…
import VueResource from 'vue-resource'
Vue.use(VueResource)
Vue.http.options.root = 'http://www.liulongbin.top:3005/'
Vue.http.options.emulateJSON = true//支持post
this.$http.get('api/getnew/'+this.id).then(result=>{
})
http://jquery.cuishifeng.cn/jQuery.Ajax.html
$.get() $.post() $.getJSON() 不需要传入对象,单个参数即可,而ajax可以传入对象
$.get('json.php', { id: 1 }, function (res) {
console.log(res)
})
// $.post('json.php', { id: 1 }, function (res) {
// console.log(res)
// })
// $.getJSON('json.php', { id: 1 }, function (res) {
// console.log(res)
// })
当然可以使用一个ajax搞定了
$.ajax({
url: '',
type: 'get',
data: { id: 1, name: '张三' },
dataType: 'json',
// 一旦设置的 dataType 选项,就不再关心 服务端 响应的 Content-Type 了
// 客户端会主观认为服务端返回的就是 JSON 格式的字符串
success:function(data){
console.log(data)
},
error:function(){
},
complete:function(){
}
})
如果想要在请求前和请求后处理一些业务逻辑
$(document)
.ajaxStart(function () {
// 只要有 ajax 请求发生 就会执行
$('.loading').fadeIn()
// 显示加载提示
console.log('注意即将要开始请求了')
})
.ajaxStop(function () {
// 只要有 ajax 请求结束 就会执行
$('.loading').fadeOut()
// 结束提示
console.log('请求结束了')
})
Fetch API 提供了一个获取资源的接口(包括跨域请求fetch-jsonp)。任何使用过 XMLHttpRequest 的人都能轻松上手,但新的API提供了更强大和灵活的功能集。
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API
这是微信小程序发送请求的API
//app.js
App({
config: {
apiBase: 'https://locally.uieee.com'
}
})
进行封装utils/fetch.js
const app = getApp()
module.exports = (url,data,methods="get")=>{
wx.showLoading({ title: 'Loading...' })
return new Promise((res, rej)=>{
wx.request({
url:app.config.apiBase+url,
data,
methods,
success:function(data){
res(data)
},
fail:function(err){
rej(err)
},
complete:wx.hideLoading()
})
})
}
引入并使用fetch代码
const fetch = require('../../utils/fetch.js')
fetch(`/shops/1`)
.then(res=>{
console.log(res.data)
})
.catch(err=>{
console.log(err)
})
art-template 是一个简约、超快的模板引擎。
前端轻量级web进度条 – Nprogress
better-scroll 是一款重点解决移动端(已支持 PC)各种滚动场景需求的插件。
我这里就不深入了…可以参考下jquery源码。
我的思路:
locallhost
来判断readyState状态
ajax进度