前端与后端的交互
- form表单提交,最原始的方法,登录框之类,input的name+value,submit提交到form的action地址上.post/get的方式提交。
举例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<form action="/form.html" method="get">
<input type="text" name="username" placeholder="username">
<input type="password" name="password" placeholder="password">
<input type="submit">
</form>
</body>
</html>
如图:随便输入,提交看看:
看看提交后跳转的页面的URL,域名加action的内容?输入的内容的组合。换句话说,浏览器构造了这个新的URL发给服务器请求。对应的关键信息服务器也收到了,服务器就会处理了。
get是把输入信息拼装成URL发过去,post是把信息直接发送到后台。
这是前端把数据给了后台。这方式很老,缺点是发送时候会跳转,就算不跳转,当前页面也会刷新,这体验就差了。还有,这是单向的,只提交后台了,后台什么响应?不知道,反正页面跳了。到底成功了?
有木有方法,可以不跳转页面,不刷新,直接发请求,收数据,并知道进程?所以ajax了。
- ajax是什么?
它是一种技术方案,就是为了解决一些问题提出的方法。它依赖现有的css/HTML/JS,算是依赖这种环境,在这个平台上实现的,最核心的依赖是浏览器提供的XMLHttpRequest对象,是这个对象使浏览器发出HTTP请求与接收HTTP响应的。实现页面不刷新的情况下和服务端交互数据。
刚开始是XML格式的数据,后来倾向于JSON格式,理论上任何格式都可以。
用JS操作XMLHttpRequest这个对象向服务器发请求,这个对象就可以得到数据了。
后来浏览器升级了,又出现了一种方案叫frtch,也可以搞定,但是比较新,所以兼容性差。所以,它也可以说是ajax的子集里。
例子来:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script>
var xhr = new XMLHttpRequest() //创建对象,XMLHttpRequest()是个函数。
//就可以在这个对象上操作,这对象可以干嘛?可以做设置,比如要发请求,发给谁,是get还是post,是同步还是异步?
//同步就是我发了请求,处于等待中卡死了,后端给我响应后,才会执行后面的代码。
//异步就是发了请求就不管了,做个事件监听的类似,内部状态改变了满足我的条件了,监听到了再做。setTimeout也是异步的,时间点到了,才执行。
xhr.open('GET','/hello.json',true)
//这是设置的方法,三个参数,请求类型是get还是post;请求地址(这里服务器先不管);异步是true.
//到了这里,还没有发,什么时候发?现在就可以:
xhr.send()
//这时候打开页面,再进入控制台,有报错,说域名是file开头,必须以http(s)开头才可,我这里在JS.bin上或者在终端的http-server上都可的。
</script>
</body>
</html>
在终端的静态服务器上打开控制台的Network,刷新页面,如图
有了请求的内容。
再看反馈
没有找到?原本写法是向hello.json里获取请求,也就是向图片中的http://192.168.1.106:8080/hello.json去获取,而这个 http://192.168.1.106:8080/hello.json 是不是存在?直接打开这个网页:
木有啊。这时候怎么办?我可以在这个路径上新建一个:
在符合这个路径上建了个文件hello.json:
{
"name":"haha",
"age":3
}
再打开 http://192.168.1.106:8080/hello.json ,如图
再刷新下http://192.168.1.106:8080/wo.html,看看还有木有报错,如图
现在又有问题了,到了之后,代码里并没有说怎么办啊,我如何去拿到数据?
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello.json',false) //同步的
xhr.send()
var date = xhr.responseText //文本内容
console.log(date) //显示出来
</script>
如图最主线的流就是,创建对象,注明请求的设置,再发送,发送了,就接收后端的数据,再针对数据进行后续设置操作。
当然,不想同步等着后台数据的到来,很多ajax都卡住了,太慢了。需要异步的方式:
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello.json',true)
xhr.send()
//可是这时候直接执行下一行,后台还没有反馈回来呢,只能是undefined了,等数据来了,代码都执行完了。
var date = xhr.responseText
console.log(date)
</script>
如图啥都没有。这时候需要干嘛?需要监听:
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello.json',true)
xhr.send()
xhr.onload = function(){
var date = xhr.responseText
console.log(date)
}
</script>
//也可以xhr.addEventListener('load',function(){
var date=xhr.responseText
console.log(date)
})
如图发了请求后就不管了,走侦听事件的流程。
一般都是用异步的。
再往细节去控制这个交互过程
- 明明有报错,可是一无所知
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello1.json',true) //请求hello1.json这个不存在的文件
xhr.send()
xhr.onload = function(){
var date = xhr.responseText
console.log(date)
}
</script>
如图有报错,但是我却不知道。
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello1.json',true)
xhr.send()
xhr.onload = function(){
console.log(xhr.status) //
var date = xhr.responseText
console.log(date)
}
</script>
如图输出了404。
输出200.
如果status是404,就是错,是200,就正常。
status是交互数据的进程的属性,所以,这时候可以做个判断了:
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello.json',true)
xhr.send()
xhr.onload = function(){
console.log(xhr.status)
if(xhr.status ===200){
var date = xhr.responseText
console.log(date)
}else{
return 'error'
}
}
</script>
如图再改成hello1.json,如图
出现了404.
但是,status不能都是200,它还有其他值的。它一般是200到300里的数表示不同状态。
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello1.json',true)
xhr.send()
xhr.onload = function(){
console.log(xhr.status) //304是走缓存的,重定向
if((xhr.status >=200 && xhr.status<300) ||xhr.status===304){
var date = xhr.responseText
console.log(date)
}else{
console.log('error')
}
}
</script>
- 其他用法
服务器根本没接收到请求:
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello1.json',true)
xhr.send()
xhr.onload = function(){
console.log(xhr.status)
if((xhr.status >=200 && xhr.status<300 )||xhr.status===304){
var date = xhr.responseText
console.log(date)
}else{
console.log('error')
}
}
xhr.onerror =function(){
console.log('error')
} //断网了,根本没到服务器的时候,可以测试下的。
</script>
- xhr.ontimeout = function(){
}超时了,比如设定时间5秒,超过了时间,请求还没到,就可以执行什么什么了。 - 再研究下onload
什么情况下叫load?
这时候需要看这个属性:xhr.onreadystatechange = function(){
},同样可写成xhr.addEventListener('readystatechange',function(){})
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello.json',true)
xhr.send()
xhr.addEventListener('readystatechange',function(){
console.log('readyState:',xhr.readyState)
})
xhr.onload = function(){
console.log(xhr.status)
if((xhr.status >=200 && xhr.status<300 )||xhr.status===304){
var date = xhr.responseText
console.log(date)
}else{
console.log('error')
}
}
xhr.onerror =function(){
console.log('error')
}
</script>
运行下,如图这是什么意思呢?我们对象里有个状态叫readyState,在交互时候,前端跟后端有几个握手的过程,我发请求了,你发了啊,我看看,看了吗,看了,可以发数据了吗,可以,什么时候,马上,,,
每一次握手,这个状态就改变了,这个事件叫readystatechange事件,表现成readyState的值。
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET','/hello.json',true)
xhr.send()
console.log('readyState:',xhr.readyState)
xhr.addEventListener('readystatechange',function(){
console.log('readyState:',xhr.readyState)
})
xhr.onload = function(){
console.log(xhr.status)
if((xhr.status >=200 && xhr.status<300 )||xhr.status===304){
var date = xhr.responseText
console.log(date)
}else{
console.log('error')
}
}
xhr.onerror =function(){
console.log('error')
}
</script>
如图到4就结束,接着返回200的状态码,所以,有时候,有些这种写法:
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200 ){
console.log(xhr.responseText)
}
}
原理是类似的。
- 说明,只要服务器收到请求,就会有readystatechange这个属性,除非断网,只是交互的状态而已。
status才是对数据的正常与否的管理。
而load是状态变成4时,就自动触发load。
走个流程看看
var xhr = new XMLHttpRequest()
xhr.open(type,URL,异步同步)
xhr.send()
xhr.ontimeout=function(){
console.log('请求超时')
}
//发送
xhr.ontimeout=function(){
console.log('请求超时')
} //请求数据没收到超时处理
xhr.readyState //交互过程从1到4的值
xhr.status //浏览器收到后端对发的请求的对错的判断
xhr.onload() //对收到数据的处理
xhr.onerror //后端没有收到请求的处理
请求的是路由
我们上面写的第二个参数是请求的地址嘛,不要把/helo.json当成文件,这是特殊例子,在静态服务器上搞的。如何理解这个参数呢?
我们请求的是一个资源,URL定位一个资源资源的名字是/helo.json。
现在我想要资源,名字叫/hello/world。这时候,需要模拟后端,接收请求。另外,请求时,会有参数,比如/login,向登录地址发请求,我们需要传递些参数的,就变成这样的结果:
'/login?username=haha&password=123'
数据拼装成URL格式了,发请求。这是对于get形式的。
post的呢?
<script>
var xhr = new XMLHttpRequest()
xhr.open('POST','/login',true) //这里不是'/login?username=haha&password=123'了
xhr.send('username=haha&password=123') //放到send这里,字符串哦。
console.log('readyState:',xhr.readyState)
xhr.addEventListener('readystatechange',function(){
console.log('readyState:',xhr.readyState)
})
xhr.onload = function(){
console.log(xhr.status)
if((xhr.status >=200 && xhr.status<300 )||xhr.status===304){
var date = xhr.responseText
console.log(date)
}else{
console.log('error')
}
}
xhr.onerror =function(){
console.log('error')
}
</script>
对应的出个函数把拼装name&password直接做出来:
mkURL({
username:'haha',
age:3
}) //数据是key,value的值,所以参数必须是对象。
function mkURL(obj){
var arr=[]
for(var key in obj){
arr.push(key + '=' +obj[key])
} //结果是要拼接,拼接了两层,各自的key,value,=拼,最后所得用&连接。
//所以需要先遍历。然后,先完成最内层拼接,最后用数组的join把各项连接。
return arr.join('&')
}
//这时候,xhr.send()的参数就是mkURL(obj)了。
封装的ajax
function ajax(opts){
var url = opts.url //参数中的URL
var type = opts.type || 'GET' //方式,默认是'GET' var dataType = opts.dataType || 'json' //返回数据类型,默认是json格式
var onsuccess = opts.onsuccess || function(){} //如果用户传递了,就用用户的,否则,,,
var onerror = opts.onerror || function(){} //如果用户传递了,用用户的,否则,,,
var data = opts.data || {} //如果用户传递了,用用户的,否则为空数据。
var dataStr = []
for(var key in data){
dataStr.push(key + '=' + data[key])
}
dataStr = dataStr.join('&')
//类似上面的那个,就是处理用户的数据
if(type === 'GET'){
url += '?' + dataStr
} //get格式的信息处理
var xhr = new XMLHttpRequest()
xhr.open(type, url, true)
xhr.onload = function(){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
//成功了
if(dataType === 'json'){
onsuccess( JSON.parse(xhr.responseText)) //收到的数据都是字符串格式,如果约定的是JSON格式,那发的就是JSON格式的字符串,再转回成onsuccess对象。
}else{
onsuccess( xhr.responseText)
}
} else {
onerror() //否则执行onerror()
}
}
xhr.onerror = onerror // 掉网了执行onerror()
//对send()的设置,是post,就有参数,否则没有参数。
if(type === 'POST'){
xhr.send(dataStr)
}else{
xhr.send()
}
}
//大纲是这个:调用ajax,就传递一个对象,对象里需要有url,type,等。
ajax({
url: 'http://api.jirengu.com/weather.php',
data: {
city: '北京'
},
onsuccess: function(ret){
console.log(ret)
},
onerror: function(){
console.log('服务器异常')
}
})
封装好了的皮:
ajax({
url: 'http://api.jirengu.com/weather.php',
type:'post',
dateType:'text',
data: {
city: '北京'
},
onsuccess: function(ret){
console.log(ret)
render(ret)
},
onerror: function(){
console.log('服务器异常')
showError()
}
})
function render(json){
} //把数据拼装成DOM放到页面上
function showError(){
}