Ajax

259 阅读7分钟

Ajax来源

浏览器和服务器间的关系

用户怎么发送数据?
数据起始是在服务器中,当用户点击后,从服务器发送过来。
可通过form表单发送数据:

<form action="/.getData.php" method="get">  
action指定提交的url,method提交的方式

form通过get提交数据的本质:
在url?后拼接上key=value
form只有在设置了name属性的表单元素才能在提交表单的时候传递他们的值

  • form
    • enctype属性
      • 规定在发送表单数据之前如何对其进行编码
      • 默认值是:application/x-www/form-urlencoded(在发送前编码所有字符)
      • 提交文件:multipart/form-data
      • 不对字符编码。当文件格式是这个的时候,必须使用改值
      • text/plain:空格转换为“+”,但不对特殊字符编码

用form点击submit自动就发送出去了,没有设置 请求行 请求主体等。缺点:一点击页面就跳转了。
想要页面不刷新实现局部刷新用ajax:就需要自己发送一个请求报文:即请求头 请求行 请求主体

HTTP协议

概念:使用请求报文和响应报文这种方式进行数据交互称为http协议。
http协议就是规定了请求报文和响应报文的格式

请求报文

浏览器发出。保存的是发送的方法,请求的url地址以及浏览器的信息和返送给服务器的数据。
请求报文=请求头+请求行+请求主体。

  • 请求行
    请求方式,请求地址
  • 请求头
    • Accept 浏览器的信息
    • Accept-Encoding 接收的语言格式
    • Accept-Language 发送的语言格式
    • 等一些浏览器信息 以及想要发送给服务器的信息
  • 请求主体
    发送给服务器的数据内容

响应报文

服务器返回的。主要是服务器的信息,浏览器可以直接看到的内容
响应报文=状态行+响应头+响应主体

  • 状态行
    请求是否成功
    请求的状态:200成功,404页面不存在,304被缓存了
  • 响应头
    服务器的一些信息。(服务器想要告诉浏览器的一些信息)
  • 响应主体
    用户能看到的内容

Ajax实现

Ajax请求

  1. 创建异步对象 XMLHttpRequest
  2. 设置请求行(get请求写在url后面).open
  3. 设置请求头(get请求可以省略,post不发送数据也可以省略) .setRequestHeader
  4. 注册回调函数 onload 异步对象.responseText
  5. 请求主体发送 .send(get请求为空,或者写null;post请求数据写在这里,如果没有数据,直接为空或null)

Ajax通过post发送请求

var xhr = new XMLHttpRequest;
xhr.open('post','postData.php')
xhr.setRequestHeader('Content-type','application/x-www-form-unlencoded')
//是表单form的entype的默认值
xhr.onload = function(){ console.log(xhr.responseText); }
xhr.send('key1value1&key2=value2')//发送数据

Ajax通过get发送请求

var xhr = new XMLHttpRequest;
xhr.open('get','getData.php?key1=value1&key2=value2') //请求的数据在这里发送
//不用设置请求头
xhr.onload=function(){
    console.log(xhr.responseText);
}
xhr.send(null)//或xhr.send()
//此处什么都不发,因为请求的数据写在了url里面

onreadystatechange

状态改变事件

  • 只要readyState属性发生变化,就会调用相应的处理函数
  • 所有浏览器都支持onreadystatechange
  • 后来许多浏览器实现了额外的事件(onload,onerror,onprogress)
  • onload,IE有兼容问题

xhr.onreadystatechange = function(){} (替换onload)

readyState属性
0 XMLHttpRequest代理已被创建,还没有调用open()方法
1 open()方法已被调用
2 send()方法已经被调用,并且头部和状态语句可获得
3 下载中,responseText属性语句包含部分数据
4 下载完成
即 与ajax创建的步骤一样,一共四步骤

get&post

get方式请求数据

  • 数据是拼接在url中的,数据的安全性不好
  • 数据的长度问题
    • 有些浏览器会限制url的长度
    • 有些服务器,对于长度太长的url直接屏蔽了
  • 优点:测试方便

post方式请求数据

  • 提交的数据不在url中,安全性好一些
  • 没有长度限制
  • 如果要上传文件,必须使用post

get还是post

  • 如果追求速度,用get发送只有少数剪短字段的小表单
  • 如果传递的是需要立即执行的命令行参数,会限制其数目或长度,对那些很多字段或很长的文本域,用post
  • 若出于安全性考虑用post。用get可从地址栏和服务器的日志文件中进行截取。post在将参数传输给服务器的时候,可用加密方式

Ajax的封装

function ajax(option){
	//获取默认值
	var url = option.url;//请求路径
	if(!url){
		console.error('请求路径必须传入');
		return;
	}
	var method = (option.method||'get').toLowerCase();//请求方法
	var data = option.data||{};
	//处理请求参数/请求主体
	var params = ""
	for(var key in data){
		params+=key+"="+data[key]+"&"
	}
	params = params.slice(0,-1);
	//获取响应成功的回调函数
	var success = option.success;
	//获取响应出错的回调函数
	var error = option.error
	//获取是否使用xhr进去数据请求
	var dataType = (option.dataType||'json').toLowerCase();
	//如果使用script标签请求数据,传给后台的回调函数名的键,默认是callback
	var jsonp = option.jsonp||'callback';
	//如果使用script标签请求数据,传给后台的回调函数名,默认是随机
	var cb = option.cb||('phone'+new Date().getTime()+Math.random().toString().slice(2));

	//如果使用xhr对象(json)请求数据
	if(dataType=="json"){
		//创建xhr对象
		var xhr = new XMLHttpRequest;
		//请求
		if(method=="get"){
			xhr.open('get',url+"?"+params);
			xhr.send(null)
		}
		if(method=="post"){
			xhr.open('post',url);
			xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
			xhr.send(params)
		}
		//响应
		xhr.onreadystatechange = function(){
			if(xhr.readyState==4){
				if(xhr.status==200){					
					success(xhr.response);
				}else{
					if(error){
						error();
					}
				}
			}
		}
	}

	//如果使用script标签请求(jsonp)数据
	//创建script标签
	var script = document.createElement('script');

	//设置该标签的src属性
	script.src =url+"?"+params+"&"+jsonp+"="+cb;								
	//定义一个函数,以备调用
	window[cb] = function(data){
		success(data);
		script.remove()
	}
	document.body.appendChild(script);
}


// ajax({
// 	method:"get/post",//请求方式是get或者post,不区分大小写,默认get
// 	url:"",//请求的路径,不需要参数
// 	data:{
// 		a:1,
// 		b:2
// 	},//请求参数或者请求主体
// 	success:function(res){
// 		//响应完成或的回调函数,res指的是响应的数据
// 	},
// 	error:function(){

// 	},
// 	dataType:'json/jsonp',//指定是使用xhr请求(json)数据还是使用script标签请求(jsonp)数据
// 	jsonp:"",//如果使用script标签请求数据,传给后台的回调函数名的键,默认是callback
// 	cb://如果使用script标签请求数据,传给后台的回调函数名,默认是随机
// })

跨域问题

1、 什么是跨域?

跨域是指浏览器不能执行其他网站的脚本。它是由浏览器的同源政策造成的,是浏览器对象JavaScript施加的安全限制

  • 同源策略:是指协议、域名、端口要相同,只有三者有一个不同就产生跨域
  • 浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。注:跨域限制访问,事实上是浏览器的限制策略,理解这一点很重要

2、三种方式解决跨域问题

  • JSONP(需要前后端配合完成)
    • 前端使用script标签来调用接口
    • 后端需要配合使用res.jsonp()返回数据
    • JSON只适用于GET请求,POST请求用不了
//第一种写法
<script>
    function handleData(res) { console.log('res',res) }
</script>
//第二种写法
<script>
    function handleData(res){ console.log('res',res) }
    var oScript = document.createElement('script');
    oScript.src = "http://localhost:8001/user/list?callback=handleData";
    oScript.type = "text/javascript";
    document.body.appendChild(oScript);
</script>
  • 代理:使用http-proxy-middleware中间件来实现代理
    • 在Node.js中使用http-proxy-middleware来进行接口代理
    • 后端还可以使用Nginx进行接口处理
    • 前端可以使用webpack进行接口代理
const app = require('express')();
const proxy = require('http-proxy-middleware');
app.use('/user',proxy({
    target:'http://10.36.136.170:9999',
    changeOrigin:true}))
  • CORS
    • 只需要后端工程师来处理
const app = require('express')();
//设置跨域访问(前端需要清除缓存后,才能再测试跨域)
app.all('*',function(req,res,next){
    res.header("Access-Control-Allow-Origin","*");
    res.header("Access-Control-Allow-Headers","X-Requested-Width");
    res.header("Access-Control-Medthods","PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By","3.2.1");
    res.header("Content-Type","application/json;charset=utf-8");
    next();
});