參考:原生 JavaScript 實現(xiàn) AJAX惩坑、JSONP
XMLHttpRequest的使用
參考:XMLHttpRequest
? XMLHttpRequest發(fā)送請求和獲取響應(yīng)
例子:
var request = new XMLHttpRequest();
request.open("GET", "get.php", true);
request.send();
//該屬性每次變化時會觸發(fā)
request.onreadystatechange = function(){
//若響應(yīng)完成且請求成功
if(request.readyState === 4 && request.status === 200){
//do something, e.g. request.responseText
}
}
發(fā)送請求:
- 建立XMLHttpRequest對象:var request = new XMLHttpRequest();
- .open初始化請求:request.open(方法名, URL, 是否異步);
- .send(data)發(fā)送數(shù)據(jù):request.send(data);
監(jiān)聽回復(fù):
? 1.服務(wù)器回復(fù)之后readystate
變化币厕,調(diào)用onreadystatechange
? 2.根據(jù)readystate
請求狀態(tài)碼,status
服務(wù)器返回的響應(yīng)狀態(tài)亲怠。處理請求成功之后服務(wù)器返回的數(shù)據(jù)
不考慮json的ajax
ajax的使用方式:
ajax({
url: 'test.php', // 請求地址
type: 'POST', // 請求類型,默認"GET"婶溯,還可以是"POST"
data: {'b': '異步請求'}, // 傳輸數(shù)據(jù)
success: function(res){ // 請求成功的回調(diào)函數(shù)
console.log(JSON.parse(res));
},
error: function(error) {} // 請求失敗的回調(diào)函數(shù)
});
需求分析:
? 根據(jù)type
的不同發(fā)送不同請求间景,根據(jù)服務(wù)器返回的狀態(tài)調(diào)用susccess
請求成功佃声,error
請求失敗函數(shù)
function ajax(params) {
let {method='GET',data={},url,success=function () {},error=function () {}}=params
let request = new XMLHttpRequest()
request.open(method,url,true)
request.send(data)
request.onreadystatechange=function () {
if(request.readyState === 4){
let status = request.status
if(request.status>=200&&request.status<300){
success(request.responseText,request.responseXML)
}else {
error(status)
}
}
}
}
功能完善:
? 1.為保證服務(wù)器接收數(shù)據(jù)正確,如果數(shù)據(jù)類型為key1=val1&key2=val2
時客戶端所發(fā)送的數(shù)據(jù)都要經(jīng)encodeURIComponent
進行編碼倘要。
? 也就是:1.1發(fā)送GET
請求
? 1.2發(fā)送POST
請求的Content-Type='application/x-www-form-urlencoded'
時
? 2.GET
方法send(null)
,POST方法根據(jù)Content-Type
的不同發(fā)送不同的數(shù)據(jù)數(shù)據(jù)類型
? 本例中的Content-Type
可為:application/json
圾亏、application/x-www-form-urlencoded
let TYPE_URLENCODED='application/x-www-form-urlencoded'
let TYPE_JSON = 'application/json'
function ajax(params) {
let method = params.method.toUpperCase()||'GET'
let data = params.data||{}
let url = params.url
let success = params.success||function () {}
let error =params.error||function () {}
let contentType = params.contentType||'application/x-www-form-urlencoded'
if(!url){
console.log('url can\'t be undefined')
return
}
const request = new XMLHttpRequest()
function urlEncodeFormat(data){
let encoded=[]
for (let key in data){
let unit=encodeURIComponent(key)+'='+encodeURIComponent(data[key])
encoded.push(unit)
}
return encoded.join('&')
}
if(method==='GET'){
data=urlEncodeFormat(data)
debugger
let url=params.url+'?'+data
request.open(method,url,true)
request.send(null)
}else if(method==='POST'){
request.open('POST',url,true)
if(contentType === TYPE_URLENCODED){
data=urlEncodeFormat(data)
}else if( contentType === TYPE_JSON){
data=JSON.stringify(data)
}
request.setRequestHeader('Content-Type',contentType)
request.send(data)
}
request.onreadystatechange = function () {
if (request.readyState === 4){
if(request.status>=200&& request.status<300){
success(request.responseText,request.responseXML)
}else{
error(request.status)
}
}
}
}
//使用示例
let baseURL='http://localhost:3333'
ajax({
url:baseURL+'/getTest',
method:'GET',
data:{
name:'get data',
data:'gggg'
},
success:function (data) {
console.log(data)
},
error:function (err) {
console.log(err)
}
})
ajax({
url:baseURL+'/postTest',
method:'POST',
data:{
name:'post data',
data:'ppppppp'
},
success:function (data) {
console.log(data)
},
error:function (err) {
console.log(err)
}
})
ajax({
url:baseURL+'/postTest',
method:'POST',
contentType:'application/json',
data:{
name:'post data',
data:'jjjjj'
},
success:function (data) {
console.log(data)
},
error:function (err) {
console.log(err)
}
})
JSONP
JSONP原理:1.<script>
標簽不受同源政策影響,可以跨域根據(jù)scr
的地址請求資源
? 2.1用<sctipt>
標簽請求到的是javascript
代碼封拧,相當于瀏覽器直接請求到了這段代碼并且執(zhí)行召嘶。服務(wù)器向客戶端jsonp傳參就是在返回的javasctipt代碼的函數(shù)中傳參,類似jsonpCallBack({data:'ddddd'})
哮缺。
? 2.2 succuss: jsonpCallBack
在發(fā)送請求前被聲明,會拿到服務(wù)器返回的參數(shù)甲喝,調(diào)用success(data)
,將參數(shù)傳給success
? 2.3 error:由于沒有使用XMLHttpRequest
尝苇,所以無法根據(jù)服務(wù)器返回狀態(tài)調(diào)用error
——>設(shè)置超時定時器,如果一段時間內(nèi)沒有調(diào)用jsonpCallBack
成功調(diào)用success
說明超時埠胖、請求錯誤
僅僅實現(xiàn)了客戶端糠溜,服務(wù)端PHP請參考:原生 JavaScript 實現(xiàn) AJAX、JSONP
let TYPE_URLENCODED='application/x-www-form-urlencoded'
let TYPE_JSON = 'application/json'
function ajax(params) {
let data = params.data||{}
let url = params.url
let success = params.success||function () {}
let error =params.error||function () {}
let jsonpCbCount=0
if(!url){
console.log('url can\'t be undefined')
return
}
function urlEncodeFormat(data){
let encoded=[]
for (let key in data){
let unit=encodeURIComponent(key)+'='+encodeURIComponent(data[key])
encoded.push(unit)
}
return encoded.join('&')
}
function normalRequest() {
let method = params.method.toUpperCase()||'GET'
let contentType = params.contentType||'application/x-www-form-urlencoded'
const request = new XMLHttpRequest()
if(method==='GET'){
data=urlEncodeFormat(data)
let url=params.url+'?'+data
request.open(method,url,true)
request.send(null)
}else if(method==='POST'){
request.open('POST',url,true)
if(contentType === TYPE_URLENCODED){
data=urlEncodeFormat(data)
}else if( contentType === TYPE_JSON){
data=JSON.stringify(data)
}
request.setRequestHeader('Content-Type',contentType)
request.send(data)
}
request.onreadystatechange = function () {
if (request.readyState === 4){
if(request.status>=200&& request.status<300){
success(request.responseText,request.responseXML)
}else{
error(request.status)
}
}
}
}
function jsonpRequest() {
let method = 'GET'
let timeout=params.timeout||1000
let data = params.data||{}
let jsonpCbFn='jsonpCb'+jsonpCbCount//每次jsonp請求返回的script調(diào)用的函數(shù)都是唯一的
jsonpCbCount++
//添加script發(fā)送請求
data.jsonpCbFn=jsonpCbFn
data= urlEncodeFormat(data)
let script = document.createElement('script')
script.src=params.url+'?'+data
let head=document.getElementsByTagName('head')[0]
head.appendChild(script)
//定義服務(wù)器返回數(shù)據(jù)時調(diào)用的函數(shù)
window[jsonpCbFn] = function (res) {
clearTimeout(timer)
head.removeChild(script)
success(res)
}
let timer = setTimeout(function () {
head.removeChild(script)
params.error('jsonp error,timeout:'+timeout)
},timeout)
}
params.jsonp?jsonpRequest():normalRequest()
}
//使用示例
let baseURL='http://localhost:3333'
ajax({
url:baseURL+'/jsonpTest',
jsonp:true,
data:{
name:'jsonp',
data:'jsonp/jsonp/jsonp'
},
success:function (data) {
console.log(data)
},
error:function (err) {
console.log(err)
}
})
?