做Web的需求一定会涉及到浏览器和服务器的交互,也就是B/S,B/S的交互又是通过HTTP协议,而post和get是HTTP协议中的两种方法。


HTTP协议规定GET是获取资源的方法,POST是创建资源的方法,PUT是更新资源的方法,DELETE是删除资源的方法,PATCH是修改资源的方法。
一个URL地址,它用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的查,改,增,删4个操作。而GET一般用于获取/查询资源信息,POST一般用于更新资源信息。

“......”
“......”

get相对post的优势是什么

GET的所有信息都在URL,也就是地址栏,所以很方便的被记录下来,
请求中的URL可以被存在各种地方,甚至被搜索引擎收录
数据比POST透明化一点,“方便大家都看得到”。

post和get的浏览器长度限制

get
get是通过URL提交数据,因此get可提交的数据量就受url的最大长度限制,HTTP协议对URL长度是没有限制的,限制URL长度多是浏览器或者服务器的配置参数。
post
HTTP协议也没有对POST进行限制,一般是受服务器配置限制或者内存大小。PHP下可以修改的配置来设置POST的大小(最初默认是8M)。

post和get的安全性

post和get都是明文传输
1.get是通过URL方式请求,可以直接看到,可能会保存在Web的日志中,也可能会保存在浏览器历史记录以及缓存中。
2.post是通过请求header请求,可以通过开发者工具或者抓包看到。
所以该https的时候还是得https

get幂等,post不幂等

幂等意味着对同一URL的多个请求应该返回同样的结果。。
1.按照RFC规范,PUT,DELETE和安全方法都是幂等的,但服务端实现是否幂等是无法确保的。
2.引入幂等主要是为了处理同一个请求重复发送的情况,比如在请求响应前失去连接,如果方法是幂等的,就可以放心地重发一次请求。
3.get请求用于信息获取,由于是安全且幂等的。一般不容易产生副作用。它仅仅是获取资源信息,不会影响资源的状态。

post不幂等,可能改变服务器上的资源的请求。

“......”
“......”

用ajax时的get

get:
数据放在url
把数据名称和数据值用=连接,如果有多个的话,那么他会把多个数据组合用&进行连接,然后把数据放到url?后面传到指定页面

1
xhr.open('get','get.php?username=hhardyy&sex=man',true);

(具体数据根据后端给的接口拼接,因为不同的需求需要的数据不一样)

后端php接收:

1
2
3
4
5
6
7
<?php
header('content-type:text/html;charset="utf-8"');
error_reporting(0);
$username=$_GET['username'];
$sex=$_GET['sex'];
echo "你的名字:{$username},性别:{$sex}";
?>

此时如果将后端改成

1
echo "你好,你的名字:{$username},性别:{$sex}";

前端

1
alert(xhr.responseText);

弹出的依旧是:你的名字:hhardyy,性别:man”;而不会弹出你好,你的名字:hhardyy,性别:man

原因就是缓存的问题,重新提交一次数据,由于url地址一样,它会读出缓存里面的而不是读出服务器里面,

get缓存问题解决方法:

在url?后面接上一个随机数或者时间戳,防止每次url一样

1
xhr.open('get','get.php?username=hhardyy&sex=man&'+ new Date().getTime(),true);

get提交中文乱码解决办法:

编码encodeURI()

1
2
xhr.open('get','get.php?username='+圳+'&sex=man&'+ new Date().getTime(),true);/弹出中文乱码
xhr.open('get','get.php?username='+encodeURI('圳')+'&sex=man&'+ new Date().getTime(),true);/正常

“......”
“......”

用ajax时的post

post:
数据放在send方法里面
enctype:提交的数据格式,默认application/x-www-form-urlencoded”application/x-www-form-urlencoded”>
意思是根据url进行编码,也可以进行二进制编码等,后端拿到之后解码就可以拿到数据了

后端php接收:

1
2
3
4
5
6
7
<?php
header('content-type:text/html;charset="utf-8"');
error_reporting(0);
$username=$_POST['username'];
$sex=$_POST['sex'];
echo "你的名字:{$username},性别:{$sex}";
?>

前端数据提交:

1
2
3
4
5
xhr.open('post','post.php',true);

xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
(声明发送的数据类型application/x-www-form-urlencoded)
xhr.send('username=hhardyy&sex=18');

post提交数据没有缓存问题

post中文编码没问题

1
xhr.send('username=圳&sex=18');

因为已经声明了发送的数据类型urlencoded,所以它自动进行url编码。

ajax

“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),节省用户操作时间,提高用户体验,减少数据请求传输获取数据等等,比传统网页刷新需要整页刷新更帅一筹,比如注册页面,
传统网页需要填完所有信息然后点击注册按钮之后,填错的地方才给出警告,而ajax不同,可以在输入文本框,比如用户名的时候通过焦点事件向后台发送ajax异步请求,当你输入完用户名想输入密码的
时候,网页就会提示用户名是否已经被注册,或者合不合法,比传统填完一大串信息最后爆出一个符号错误又得回去修改整页的感觉nice好多。

请求状态监控

onreadystatechange(目前已经不推荐使用了,建议用load),理由呢,我写分别写出来,拿get来举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
alert(xhr.responseText);
}
}
}
xhr.open('get', 'url', true);
xhr.send();

各种请求状态的情况
0 (初始化)还没有调用open()方法
1 (载入)已调用send()方法,正在发送请求
2 (载入完成)send()方法完成,已收到全部响应内容
3 (解析)正在解析响应内容
4 (完成)响应内容解析完成,可以在客户端调用了

load

1
2
3
4
5
6
var xhr = new XMLHttpRequest();
xhr.onload = function() {
alert(xhr.responseText);
}
xhr.open('get', 'url', true);
xhr.send();

responseText:返回以文本形式存放的内容
responseXML:返回XML形式的内容

返回数据的处理

特别提醒一下,假如要解析JSON的时候需要注意,因为有Eval和JSON.parse两种方法将字符串解析成对象,两者的区别就是Eval属于饥不择食的那种,什么都转,所以不是特别安全,假如一些恶意代码什么的它也会正常解析,这就不太和谐了,所以一般推荐JSON.parse()来将字符串转成对象。

eval与JSON.parse详解

eval:可以解析任何字符串变成js(缺点:什么都能解析,比如植入的一些病毒,木马什么的,它也会解析)
parse:只能解析json形式的字符串,json必须是严格模式的json,也就是key和value都要加引号(安全性高一些,对数据来说尽量用它)
另外还有个新东西stringify()
stringify(json)(将json转换成字符串,转成严格模式的字符串),也可以用于对对象的克隆和引用,就像这样

1
2
3
4
5
6
var a={
name:"hhardyy"
}
var b=a;
b.name="xiaofangkuai"
console.log(a.name)//xiaofangkuai

很明显对象a的属性被影响了,用浅拷贝来解决问题

1
2
3
4
5
6
7
8
9
var a={
name:"hhardyy"
}
var b={}
for(var attr in a){
b[attr]=a[attr];
}
b.name="xiaofangkuai"
console.log(a.name)//hhardyy

这样虽然,互不影响了但是这个只是浅拷贝,假如a的属性里面是多个json值就得用递归一层一层….显然不是特别厉害,厉害的解决方案是深拷贝,也就是新方法登场的时候

1
2
3
4
5
6
7
var a={
name:{age:100}
};
var str=JSON.stringify(a);
var b=JSON.parse(str);
b.name.age=200;
console.log(a.name.age)//100

但是IE6、7不兼容,兼容的方法也简单,勉强用evel或者去json的官网下载json类下面的json2.js,然后引入,就可以兼容了

跨域方案

既然ajax涉及了交互请求,那么就分成当前域名下和其他域名下,也就是请求地址,请求同一地址下面的数据,可以不用跨域,假设一个域名下的文件请求另外一个域名下的资源,就产生了跨域,提到跨域都会想到jsonp解决。

什么是跨域

指的是浏览器不能执行其他网站的脚本,它是由浏览器的同源策略造成的,是浏览器施加的安全限制
所谓同源是指:域名、协议、端口号均相同。

解决跨域的方案

1、JSONP:动态插入javascript标签(浏览器对SRC属性没有同源限制),但是要注意JSONP只支持GET请求,不支持POST请求
2、代理:通过服务器来发送请求,然后将请求的结果返回给前端
3、XHR2:全称“XMLHttpRequest Level2”是HTML5提供的方法,对跨域访问提供了很好的支持
4、中间件proxy

1
2
header('Access-Control-Allow-Origin:*')//允许所有来源访问
header('Access-Control-Allow-Method:POST,GET')//允许访问的方式

jsonp

全称json padding,jsonp实现跨域的原理和script标签加载的差不多,用script标签加载资源是没有跨域问题的,在资源加载进来之前定义好一个函数,这个函数接收一个参数(数据),函数里面利用这个参数做一些事情,然后需要的时候通过script标签加载对应远程文件资源,当远程的文件资源被加载进来的时候,就会去执行我们前面定义好的函数,并且把数据当作这个函数的参数传入进去。
就是像这样:

1
2
3
var oScript = document.createElement('script');
oScript.src = 'getData.php';
document.body.appendChild(oScript);

可以利用这个原理将函数封装成按需加载的样子,然后写一个函数func(data),就可以在func里头对数据data进行操作

1
2
3
var oScript = document.createElement('script');
oScript.src = 'getData.php?callback=func';
document.body.appendChild(oScript);

服务器代理

举例node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const https=require('https')
const server=https.createServer((req,res)=>{
https.get('xxxxxx.com',(resp)=>{
let data=""
//数据到达
resp.on('data',chunk=>{
data+=chunk
})
//结束
resp.on('end',()=>{
res.writeHead(200,{
'Content_Type':'application/json;charset=utf-8'
})
res.end(data)//输出data
})
})
})
server.listen(666666)

proxy中间件

举例express

1
2
3
4
5
6
7
8
9
10
11
12
const app=express()
const proxy=require('http-proxy-middleware')//单线程的跨域中间件,用于连接,快速和浏览器同步

app.use('/',proxy({ // '/'限定中间件的使用范围
target:'xxxxx.com',
pathRewrite:{
'^/':'' // '^/mock':'/mock'
},
changeOrigin:true // 允许跨域
}))
app.listen(66666)
console.log('start')

更厉害的跨域方案

就是后端的一些配合,在标准浏览器下,XMLHttpRequest对象已经是升级版本,支持了更多的特性,可以直接跨域了。前提是服务器端设置请求头,例如xxx.php中:header(“xxx:协议+域名”),既然提到了新特性,就要提到咱们的IE同志,因为IE如果想实现跨域请求,则需要使用另一个对象去实现,那就是xDomainRequest,而不是兼容XMLHttpRequest,写法看下面

1
2
3
4
5
6
var oXDomainRequest=new XDmainRequest();
oXDomainRequest.onload=function(){
alert(this.responseText);
}
oXDomainRequest.open('get','url',true);
oXDomainRequest.send();

封装了一个ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function ajax(method, url, data, success) {
var xhr = null;
try {
xhr = new XMLHttpRequest();
} catch (e) {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}

if (method == 'get' && data) {
url += '?' + data;
}

xhr.open(method,url,true);
if (method == 'get') {
xhr.send();
} else {
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
xhr.send(data);
}
xhr.onreadystatechange = function() {
if ( xhr.readyState == 4 ) {
if ( xhr.status == 200 ) {
success && success(xhr.responseText);
} else {
alert('出错了,Err:' + xhr.status);
}
}

}
}