前后端交互-ajax
谢谢大海老师,这里主要是参考了大海老师的笔记和示例,非常喜欢大海老师的讲课,也把自己所学分享给大家,希望大家共同进步,有什么意见或者建议都可以留言,enjoy!
利用ajax来解决验证用户名问题
-
ajax是: Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML)
-
ajax的基本使用;
-
新建XMLHttpRequest对象;
let xhr = new XMLHttpRequest();
-
配置请求参数
xhr.open("get","/checkUser",true); //true是异步,false是同步
-
接收返还值
xhr.onload = function(){ let res = JSON.parse(xhr.responseText); }
-
发送服务器
xhr.send();
-
示例 login.html
login.html
<body>
<div class='wrapper'>
<h1> 登录</h1>
<form action='/checkUser' methods='post'>
姓名:
<input class='inputStyle' type='text' name='username'>
<div class='exchange'>用户名错误</div>
<br/>密码:
<input class='inputStyle' type='password' name='pwd'><br/>
<input class='loginStyle' type='submit' value='登录'>
<!-- 当点击submit的时候,跳转到/checkUser地址 -->
</form>
</div>
<script>
document.querySelector('.inputStyle').onblur = function (){
let xhr = new XMLHttpRequest()
// true表示异步
// 设置配置,用get方式,到这个地址顺便传参,是异步
xhr.open('get', `/checkUserName?username=${this.value}`,true)
// 后台的结果返还到onload里面
xhr.onload = function (){
// 接收后端ctx.body里面的内容
let obj = JSON.parse(xhr.responseText)
document.querySelector('.exchange').innerHTML = obj.info
if(obj.status === 1){document.querySelector('.exchange').style.color='green'
}else{document.querySelector('.exchange').style.color='red'
}
}
xhr.send()
}
</script>
</body>
app.js
// 因为ajax接收是get,所以这里用get
router.get('/checkUserName',(ctx, next) => {
console.log(ctx.query.username)
let res = usersData.find(user => user.name === ctx.query.username)
// 接收前端的query信息
if(res){
ctx.body = {
status: 1,
info: '用户名正确'
}
}else{
ctx.body = {
status: 2,
info: '用户名错误'
}
}
})
针对ajax的详细解释
-
get注意点
- get通过parmas传参
- get和querystring的问题,通过url传参
-
post注意点
-
发送数据时候需要设置http正文头格式;
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //默认编码 xhr.setRequestHeader("Content-type","multipart/form-data"); //二进制编码 xhr.setRequestHeader("Content-type","application/json"); //json编码
-
获取头部信息;
- getAllResponseHeaders 或者是getResponseHeader ;
-
示例 post
<button>点击我发送ajax</button>
<script>
document.querySelector('button').onclick = function (){
let xhr = new XMLHttpRequest()
xhr.open('POST','/post' , true)
xhr.onload = function (){
console.log(xhr.responseText)
// 获取返还头信息
console.log(xhr.getAllResponseHeaders())
console.log(xhr.getResponseHeader('content-type'))
}
// xhr.setRequestHeader('content-type', 'application/x-www-form-urlencode')
// let data = 'username=joy&age=20'
// 设置JSON传输
xhr.setRequestHeader('content-type', 'application/json')
let data = JSON.stringify({
name: 'joy',
age: 15
})
xhr.send(data)
}
</script>
onreadystatechange
onreadystatechange:存有处理服务器响应的函数,每当 readyState 改变时,onreadystatechange 函数就会被执行。
readyState:存有服务器响应的状态信息。
- 0: 请求未初始化(代理被创建,但尚未调用 open() 方法)
- 1: 服务器连接已建立(
open
方法已经被调用) - 2: 请求已接收(
send
方法已经被调用,并且头部和状态已经可获得) - 3: 请求处理中(下载中,
responseText
属性已经包含部分数据) - 4: 请求已完成,且响应已就绪(下载操作已完成)
status常用状态码
HTTP状态码 | 描述 |
100 | 继续。继续响应剩余部分,进行提交请求 |
200 | 成功 |
301 | 永久移动。请求资源永久移动到新位置 |
302 | 临时移动。请求资源零时移动到新位置 |
304 | 未修改。请求资源对比上次未被修改,响应中不包含资源内容 |
401 | 未授权,需要身份验证 |
403 | 禁止。请求被拒绝 |
404 | 未找到,服务器未找到需要资源 |
500 | 服务器内部错误。服务器遇到错误,无法完成请求 |
503 | 服务器不可用。临时服务过载,无法处理请求 |
-
返还数据类型
-
服务器返还json数据
xhr.responseText //来获取
-
服务器返还xml数据
xhr.responseXML //获取值
- 重写response里的content-type内容
- xhr.overrideMimeType(‘text/xml; charset = utf-8’)
-
-
同步及异步ajax;
- 设置true和false区别;
示例一 readyState
readyState.html
<button>点击</button>
<script>
let xhr = new XMLHttpRequest()
xhr.open('get', '/get/3', true)
// xhr.onload = function () => {
// console.log(xhr.responseText)
// }
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
console.log(xhr.responseText)
}
}
}
// 效果同上
</script>
app.js
//这样的配置,/get/后面的数字必须得填
router.get('/get/:id', ctx => {
console.log(ctx.params)
ctx.body = {
status: 1,
info: '请求成功'
}
})
示例二 xml
xml.html
<body>
<button>点击获取</button>
<script>
document.querySelector('button').onclick = function (){
let xhr = new XMLHttpRequest()
// 如果后端没有指定content-type类型,可以在前端重写。
xhr.overrideMimeType('text/xml')
xhr.open('get', '/xml', true)
xhr.onload = function (){
// 获取XML内容
let name = xhr.responseXML.getElementsByTagName('name')[0]
console.log(name)
}
xhr.send()
}
</script>
</body>
app.js
router.get('/xml', ctx => {
// 头信息可以在后端配置,也可以在前端配置
//ctx.set('content-type', 'text/xml')
ctx.body = `<?xml version='1.0' encoding='utf-8'?>
<books>
<nodejs>
<name>nodejs实战</name>
<price>30元</price>
</nodejs>
<react>
<name>react入门</name>
<price>40元</price>
</react>
</books>
`
})
利用FormData来实现文件上传
-
创建FormData对象
-
监控上传进度
upload 事件
- onloadstart 上传开始
- onprogress 数据传输进行中
- evt.total :需要传输的总大小;
- evt.loaded :当前上传的文件大小;
- onabort 上传操作终止
- onerror 上传失败
- onload 上传成功
- onloadend 上传完成(不论成功与否)
示例 file
app.js
const Koa = require('koa')
const Router = require('@koa/router')
const Nunjucks = require('nunjucks')
const KoaBody = require('koa-body')
const koaStaticCache = require('koa-static-cache')
const fs = require('fs')
const app = new Koa()
const router = new Router()
app.use(KoaBody({
// 上传文件需要
multipart: true
}))
app.use(koaStaticCache('./template', {
prefix: '/',
dynamic: true,
gzip: true
}))
Nunjucks.configure('./template', {
// 不缓存,便于开发
noCache: true,
// 监听变化
watch: true
})
router.post('/upload', async ctx => {
let {path, name}= ctx.request.files.file
//console.log(path)
let myFile = fs.readFileSync(path)
// 第一个参数,上传文件的路径,第二个参数,读取文件的内容
fs.writeFileSync('resource/' + name, myFile)
ctx.body = '请求成功'
})
app.use(router.routes())
app.listen('8888', () => {
console.log('服务器已启动')
})
template/file.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>file</title>
</head>
<body>
<input type='file'>
<p>进度: <progress value='0' max="100"></progress><span class='percent'>0%</span></p>
<p>速度: <span class='speed'>0b/s</span></p>
<button>上传文件</button>
<button>取消上传</button>
<script>
let SLoad
let STime
let xhr = new XMLHttpRequest()
let buttons = document.querySelectorAll('button')
buttons[0].onclick = function (){
let file = document.querySelector('input').files[0]
// 实例化一个form对象
let form = new FormData()
// 插入属性,值键对应
form.append('file', file)
// xhr的配置,post,到/upload地址,异步,如果同步会阻塞
xhr.open('POST', '/upload', true)
xhr.onload = function (){
// 接收后端数据
console.log(xhr.responseText)
}
// 传送表格,form表单不需要配置头信息
xhr.send(form)
}
xhr.upload.onloadstart = function (){
console.log('开始上传')
STime = new Date().getTime()
SLoad = 0
}
xhr.upload.onprogress = function (e){
// e.loaded表示当前下载量,e.total表示总下载量
let percent = (e.loaded / e.total * 100).toFixed(0)
document.querySelector('progress').value = percent
document.querySelector('.percent').innerHTML = percent + '%'
let ETime = new Date().getTime()
let difTime = (ETime - STime) / 1000
let theLoad = e.loaded - SLoad
let speed = (theLoad / difTime).toFixed(0)
let unit = 'b/s'
STime = new Date().getTime()
SLoad = e.loaded
// 修改单位
if(speed / 1024 > 1){
unit = 'kb/s'
speed = speed / 1024
}
if(speed / 1024 > 1){
unit = 'mb/s'
speed = speed / 1024
}
document.querySelector('.speed').innerHTML = speed.toFixed(2) + unit
console.log('正在上传')
}
xhr.upload.onload = function (){
console.log('上传成功')
}
xhr.upload.onloadend = function (){
console.log('上传完成')
}
// 取消上传钩子
xhr.upload.onabort = () => {
console.log('取消上传')
}
buttons[1].onclick = function (){
// 调用钩子
xhr.abort()
}
</script>
</body>
</html>