可以如何发送请求
-
用
<form>
可以发请求,但是会刷新页面或新开页面<form action='xxx' method='get'> <input type='password' name='password'> <input type='submit'> </form>
- 用
<a>
只可以发 get 请求,但是也会刷新页面或新开页面 - 用
<img>
只可以发 get 请求,但是只能以图片的形式展示 - 用
<link>
只可以发 get 请求,但是只能以 CSS、favicon 的形式展示 - 用
<script>
只可以发 get 请求,但是只能以脚本的形式运行
❓有没有什么方式可以实现:get、post、put、delete 请求都行,想以什么形式展示就以什么形式展示❓
ajax
Asynchronous Javascript And XML
异步 Javascript 和 XML
需要满足下面三个条件,可以称之为 ajax:
- 使用 XMLHttpRequest 发请求
- 服务器返回 XML 格式的字符串
- JS 解析 XML,并更新局部页面
不过随着技术发展,XML 越来越不常用,经常使用 JSON 代替 XML
version1.0
我们尝试做一个按钮,点击向服务器发送一个请求
html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax_html</title>
</head>
<body>
<button id='myButton'>点我</button>
</body>
<script src='./main.js'></script>
</html>
main.js :
myButton.addEventListener=('click',function(e){
var request= new XMLHttpRequest(); //新建请求
request.onreadystatuschange=function(){ //当请求的状态有变化时,打印出状态码
console.log(request.readyStatus);
}
request.open('GET','/xxx'); //初始化,GET 方法,/xxx 路径
request.send(); //发送请求
})
后端代码 :
}else if(path==='/xxx'){
response.statusCode = 200
response.setHeader('Content-Type', 'text/xml;charset=utf-8')
response.write(`
//xml
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
`)
response.end()
}
效果 :
当点击 点我 按钮时,首先,新建一个XMLHttpRequest
请求;其次,使用 GET 方法请求到 /xxx;最后,发送请求。
当服务器收到请求了 /xxx 路径,然后,就返回了一串格式符合 XML 的字符串
并且,当请求和响应进行到各个状态时,都会打印出它的状态码
(状态码请参考:https://developer.mozilla.org...)
version2.0-获取xml
除了可以获取状态码、在浏览器控制台获取服务器返回的XML字符串外,还可以将XML字符串转换为XML。
并且可以使用DOM获取元素的API,来获取XML的元素,例如getElementByTagNames
...
修改后的 main.js 如下所示,新增内容和注释如??所指。
main.js :
myButton.addEventListener=('click',function(e){
var request= new XMLHttpRequest(); //新建请求
request.onreadystatuschange=function(){
console.log(request.readyStatus); //当请求的状态有变化时,打印出状态码
if(request.readyStatus === 4){ ?//表示请求响应都已经完成
if(request.status === 200){ ?//表示服务器返回成功
?//下面三句 let 用来获取返回的 xml,而不再是之前字符串格式
let parser = new DOMParser();
?//返回的内容可以用 responseText 获取
let xmlDoc = parser.parseFromString(request.responseText,'text/xml');
let title = xmlDoc.getElementsByTagNames('heading')[0].textContent;
}
}
}
request.open('GET','/xxx'); //初始化,GET 方法,/xxx 路径
request.send(); //发送请求
})
version3.0-JSON
由于 xml 看上去不够简洁,而且实际使用中,获取的方式比较繁琐(参考上面的三句 let),所以,发明了一个新的数据格式化语言——JSON,用以替代 xml。
(JSON参考官网:http://www.json.org/)
JSON vs. Javascript:
- 没有 function,undefined
- 字符串首尾必须是双引号 ""
- 没有 变量
- 没有 原型链
修改后端代码,使其返回一个JSON,??为修改处。
后端代码 :
}else if(path==='/xxx'){
response.statusCode = 200
response.setHeader('Content-Type', 'text/json;charset=utf-8') //?xml修改成json
response.write(`
//json //??返回json而不是xml
{
"note":{
"to":"Tove",
"from":"Jani",
"heading":"Reminder",
"body":"Don`t forget me this weekend!"
}
}
`)
response.end()
}
由于服务器返回的只能是一个字符串(响应第4部分只能是字符串),所以,我们也需要将返回的JSON字符串转换为一个对象,方便操作。
接下来,可以使用js对对象的操作,获取json的内容。
修改后的前端代码,?为修改处。
main.js :
myButton.addEventListener=('click',function(e){
var request= new XMLHttpRequest(); //新建请求
request.onreadystatuschange=function(){
console.log(request.readyStatus); //当请求的状态有变化时,打印出状态码
if(request.readyStatus === 4){ //表示请求响应都已经完成
if(request.status === 200){ //表示服务器返回成功
console.log("请求成功");
let string=request.responseText; ?//获取服务器返回的字符串
let jsonObject=window.JSON.parse(string); ?//将返回的字符串变成对象
console.log(jsonObject.note); ?//输出对象里的note
console.log(jsonObject.note.from); ?//输出对象里的note里的from
}
}
}
request.open('GET','/xxx'); //初始化,GET 方法,/xxx 路径
request.send(); //发送请求
})
同源策略&CORS跨域
和<form>
表单提交内容不一样,AJAX不刷新页面,并且可以读取响应内容,所以被浏览器认为是不安全的,
所以:
只有 协议+域名+端口 一模一样的时候,才允许发送AJAX请求
Σ(っ °Д °;)っ
那要是我必须需要另一个网站的接口怎么办???
如果http://www.kitty.com
想要访问http://www.ben.com
的一个接口,那Ben只需要在后端代码里加上一句话,告诉浏览器,http://www.kitty.com
和http://www.ben.com
是友好关系,可以互相访问。
Ben的后端代码:
}else if(path==='/xxx'){ //请求的接口
response.statusCode = 200 //返回状态码
response.setHeader('Content-Type', 'text/json;charset=utf-8') //设置返回类型为json
?//此句开启友好模式
response.setHeader('Access-Control-Allow-Origin', 'http://www.kitty.com')
response.write(`
//json
{
"note":{
"to":"Tove",
"from":"Jani",
"heading":"Reminder",
"body":"Don`t forget me this weekend!"
}
}
`)
response.end()
}
添加response.setHeader('Access-Control-Allow-Origin', 'http://www.kitty.com')
,浏览器就知道,Kitty和Ben是好朋友,可以互相访问啦!!!
上述方法称之为:
Cross-Origin Resource Sharing → CORS
使用Javascript发送任意格式的请求
AJAX还允许用户使用Javascript设置一个请求的任意部分,并且可以获取一个响应的任意部分。
一个请求:
GET /xxx HTTP/1.1 //第一部分,方法、地址、协议、协议版本号
HOST: //第二部分,包含很多行,包含很多内容
Content-Type: //第二部分,包含很多行,包含很多内容
//第三部分,一个回车
这里是请求体 //第四部分
一个响应:
Http/1.1 200 OK //第一部分,协议、协议版本号、状态码、状态信息
Content-Type: //第二部分,
//第三部分,一个回车
这里是响应体 //第四部分
发送一个任意的请求&获取一个响应任意部分:
myButton.addEventListener=('click',function(e){
var request= new XMLHttpRequest(); //新建请求
request.open('GET','/xxx'); //设置请求第一部分:方法、路径
request.setRequestHeader('Content-Type','x-www-form-urlencoded); //设置请求第二部分
request.send('虽然我是GET,但我也有请求体'); //设置请求第四部分
request.onreadystatuschange=function(){
console.log(request.readyStatus); //当请求的状态有变化时,打印出状态码
if(request.readyStatus === 4){ //表示请求响应都已经完成
if(request.status === 200){ //表示服务器返回成功
console.log("请求成功");
console.log(request.status) //获取响应第一部分,状态码
console.log(request.statusText) //获取响应第一部分,状态信息
console.log(request.getResponseHeader('Content-Type')) //获取响应第二部分
console.log(request.getAllResponseHeaders); //获取所有响应第二部分
console.log(request.responseText); //获取响应第四部分
}
}
}
})
总结:
总之,就是AJAX允许用户使用Javascript设置任意一个请求(浏览器不让设置的内容不能设置),也能获取一个响应的任意部分。
使用 JS 设置任意请求 header
- 第一部分:request.open('get','/xxx')
- 第二部分:request.setHeader('Content-type','x-www-form-urlencoded')
- 第四部分:request.send('a=1&b=2')
使用 JS 获取任意响应 header
- 第一部分:request.status / request.statusText
- 第二部分:request.getResponseHeader() / request.getAllResponseHeaders()
- 第四部分:request.responseText
封装ajax
我们的目标是只使用一个函数,就能实现下面发送请求的功能:
- request.open('GET','/xxx');
- request.onreadystatuschange=function(){}
- request.send('虽然我是GET,但我也有请求体');
version1.0
封装后的前端代码:
window.jquery=function(){}
window.$=window.jquery;
window.jquery.ajax=function(url,method,body,successFn,failFn){
var request = new XMLHttpRequest(); //新建请求
request.open(method,url); ?//传入发送请求方式、请求地址
request.send(body); ?//传入请求体
request.onreadystatuschange=function(){
console.log(request.readyStatus); //当请求的状态有变化时,打印出状态码
if(request.readyStatus === 4){ //表示请求响应都已经完成
if(request.status === 200){ //表示服务器返回成功
successFn.call(undefined,request.responseText); ?//响应成功,调用传入的成功函数
}else if(request.status >= 400){
failFn.call(undefined,request); ?//相应失败,调用传入的失败函数
}
}
}
}
myButton.addEventListener=('click',function(e){
window.jquery.ajax(
'/xxx',
'GET',
'虽然我是GET,但我也有请求体'
function(){},
function(){}
)
})
实现的功能是一样的,只是将ajax封装在一个函数里,之后调用只需要调用一个函数,出入响应的参数就能实现发送请求的功能。
version2.0
上个版本封装的很好,但是有几个问题:
- 需要传入的参数太多,可能是不是会忘了需要传入什么参数,无法快速的知道参数含义
- 当有一个参数用户不想传入的时候,只能使用
null
进行占位,很麻烦
所以,我们想到,给它传入一个集成的参数,把需要的参数都放在一个对象里,这样可以给参数指定名字,调用时,可以调用对象里的名字。
修改封装后的前端代码:
window.jquery=function(){}
window.$=window.jquery;
window.jquery.ajax=function(option){ ?//由原来的传入一个个的参数,变为传入包含所有参数的对象
?//首先获取参数对象里的各个值
let url=option.url;
let method=option.method;
let body=option.body;
let successFn=option.successFn;
let failFn=option.failFn;
var request = new XMLHttpRequest(); //新建请求
request.open(method,url); //传入发送请求方式、请求地址
request.send(body); //传入请求体
request.onreadystatuschange=function(){
console.log(request.readyStatus); //当请求的状态有变化时,打印出状态码
if(request.readyStatus === 4){ //表示请求响应都已经完成
if(request.status === 200){ //表示服务器返回成功
successFn.call(undefined,request.responseText); //响应成功,调用传入的成功函数
}else if(request.status >= 400){
failFn.call(undefined,request); //相应失败,调用传入的失败函数
}
}
}
}
myButton.addEventListener=('click',function(e){
window.jquery.ajax(
?//由原来的传入一个个的参数,变成现在传入一个包含所有参数的对象
{
url: '/xxx',
method: 'GET',
body: '虽然我是GET,但我也有请求体'
successFn: function(){},
failFn: function(){}
}
)
})
version3.0
我们还需要封装发送请求头:
再次修改封装后的前端代码:
window.jquery=function(){}
window.$=window.jquery;
window.jquery.ajax=function(option){ //由原来的传入一个个的参数,变为传入包含所有参数的对象
//首先获取参数对象里的各个值
let url=option.url;
let method=option.method;
let body=option.body;
let successFn=option.successFn;
let failFn=option.failFn;
let headers=option.headers; ?//获取参数对象里的headers
?//遍历headers,将里面的键、值都设置在请求头里
for(let key in headers){
let value=headers[key];
request.setRequestHeader(key,value);
}
var request = new XMLHttpRequest(); //新建请求
request.open(method,url); //传入发送请求方式、请求地址
request.send(body); //传入请求体
request.onreadystatuschange=function(){
console.log(request.readyStatus); //当请求的状态有变化时,打印出状态码
if(request.readyStatus === 4){ //表示请求响应都已经完成
if(request.status === 200){ //表示服务器返回成功
successFn.call(undefined,request.responseText); //响应成功,调用传入的成功函数
}else if(request.status >= 400){
failFn.call(undefined,request); //相应失败,调用传入的失败函数
}
}
}
}
myButton.addEventListener=('click',function(e){
window.jquery.ajax(
?//在参数对象里传入headers,里面包括了想要设置的请求头的键、值
{
url: '/xxx',
method: 'GET',
headers: {
'content-type': 'application/x-www-form-urlencoded',
'color': 'red'
}
body: '虽然我是GET,但我也有请求体'
successFn: function(){},
failFn: function(){}
}
)
})
运用jQuery使用ajax
请参考jQuery文档:https://api.jquery.com/jQuery...
题外话
计算代码执行时间
下列代码可以计算从console.time()
到console.timeEnd()
之间代码执行的时间
console.time()
//your code
console.timeEnd()
结构化编程:
- 顺序执行
- if...else...
- while/for
ES6解构赋值
使用ES6解构赋值新语法可以简化下列代码:
window.jquery.ajax=function(option){
let url=option.url;
let method=option.method;
let body=option.body;
let successFn=option.successFn;
let failFn=option.failFn;
let headers=option.headers;
//your code
}
解构之后:
window.jquery.ajax=function(option){
let {url,method,body,successFn,failFn,headers}=option;
//your code
}
更加高级点:
window.jquery.ajax=function({url,method,body,successFn,failFn,headers}){
//your code
}
?直接从window.jquery.ajax=function(){}
的第一个参数里解构,并用let
声明!!!
version4.0-Promise
当用户要使用很多ajax的时候,用i定义的或者别人自定义的,这样,每个人ajax的接口名称都不一样,用起来很麻烦,这时候,我们可以使用Promise技术
使用Promise和then:
??为修改处
window.jquery=function(){}
window.$=window.jquery;
window.jquery.ajax=function({url,method,body,headers}){
?//使用ES6解构新语法,并且删除了successFn、failFn
?//promise和之后使用ajax时的then一起,可以自动判断成功函数和失败函数
return new Promise(function(resolve,reject){
//遍历headers,将里面的键、值都设置在请求头里
for(let key in headers){
let value=headers[key];
request.setRequestHeader(key,value);
}
var request = new XMLHttpRequest(); //新建请求
request.open(method,url); //传入发送请求方式、请求地址
request.send(body); //传入请求体
request.onreadystatuschange=function(){
console.log(request.readyStatus); //当请求的状态有变化时,打印出状态码
if(request.readyStatus === 4){ //表示请求响应都已经完成
if(request.status === 200){ //表示服务器返回成功
?//响应成功,调用传入的成功函数,修改sucessFn为resolve
resolve.call(undefined,request.responseText);
}else if(request.status >= 400){
?//响应成功,调用传入的成功函数,修改failFn为reject
reject.call(undefined,request); //相应失败,调用传入的失败函数
}
}
}
})
}
myButton.addEventListener=('click',function(e){
window.jquery.ajax(
//在参数对象里传入headers,里面包括了想要设置的请求头的键、值
{
url: '/xxx',
method: 'GET',
headers: {
'content-type': 'application/x-www-form-urlencoded',
'color': 'red'
}
body: '虽然我是GET,但我也有请求体'
}
).then(function(){},function(){})
?//这就是promise,就是在ajax后面加上then,
?//传入第一个函数会被当成是成功时调用的函数,第二个函数会被当成失败时调用的函数
})
如果需要多次处理:
//your code
myButton.addEventListener=('click',function(e){
window.jquery.ajax(
//在参数对象里传入headers,里面包括了想要设置的请求头的键、值
{
url: '/xxx',
method: 'GET',
headers: {
'content-type': 'application/x-www-form-urlencoded',
'color': 'red'
}
body: '虽然我是GET,但我也有请求体'
}
).then(
function(){
//your code
return xxx;
},
function(){})
.then(
function(){},
function(){})
?//这就是promise,就是在ajax后面加上then,
?//传入第一个函数会被当成是成功时调用的函数,第二个函数会被当成失败时调用的函数
?//当需要多次调用,可以在then的函数里直接return,return的内容会被当成之后then的输入,直接处理
})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。