前后端交互-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>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值