1. HTTP各版本的区别
HTTP1.0
特点:默认短链接,明文传输
HTTP1.1
特点: 默认长连接
处理过程:支持管道通信(串行请求),发送完一个请求,不必等待另一个回来,可以继续发送下一个
缺点:服务器按照顺序响应,如果前面的请求处理耗时,后面的请求边会延迟处理,形成队头阻塞
HTTP2.0
1.HPACK 算法:客户端与服务端各维护header字段表,发送的是header索引
2.头信息帧和数据帧, 接收方不需要在对明文转二进制,可以直接解析二进制数据。
3.多路复用:数据包不再按照顺序发出,一个连接可以发送多个请求和响应
每个包叫做数据流,每个数据流都标记着一个独一无二的编号,其中规定客户端发出的数据流编号为奇数, 服务器发出的数据流编号为偶数
移除了 HTTP/1.1 中的串行请求,不需要排队等待,也就不会再出现「队头阻塞」问题,降低了延迟,大幅度提高了连接的利用率。
4.支持设置请求优先级
5.服务器主动发送数据给客户端
6.由于浏览器要求只有支持了https的网站才能升级HTTP2.0,所以也可以从这个角度说成,HTTP2.0 基于HTTPS,是安全的。
缺点:多个HTTP请求复用一个tcp 连接,如果发送丢包,就会触发TCP丢包重传的机制,所有的请求,都要等待丢的包回来再继续
HTTP3.0
传输层的TCP,换成了UDP。UDP 是不管顺序和不管丢包的,所以不会出现队头阻塞和丢包阻塞。
UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响。
QUIC 是一个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议。
QUIC 是新协议,对于很多网络设备,根本不知道什么是 QUIC,只会当做 UDP,这样会出现新的问题。所以 HTTP/3 现在普及的进度非常的缓慢.
总结
2.HTTP
HTTP 是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」
「200 OK」是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据。
「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。
「206 Partial Content」是应用于 HTTP 分块下载或断电续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
「302 Moved Permanently」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。
301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。
「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误。
「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。
「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
「501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。
「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
「503 Service Unavailable」表示服务器当前很忙,暂时无法响应服务器,类似“网络服务正忙,请稍后重试”的意思。
常见字段
host: 域名
Connection 字段最常用于客户端要求服务器使用 TCP 持久连接,以便其他请求复用。
HTTP/1.1 版本的默认连接都是持久连接,但为了兼容老版本的 HTTP,需要指定 Connection 首部字段的值为 Keep-Alive。
Connection: keep-alive
Accept 字段, 客户端声明自己可以接受哪些数据格式。
Accept: / 可以接受任何格式的数据。
Accept-Encoding 字段说明自己可以接受哪些压缩方法
Accept-Encoding: gzip, deflate
Content-Type:告诉服务端,本次数据是什么格式(表单、文件、json/xml)
application/x-www-form-urlencoded:主要向服务器提交用户隐私相关的信息(浏览器支持)
multipart/form-data: 向服务器上传小文件(浏览器支持)
application/json:向后台服务器提交结构化数据(RESTful 设计风格需要)
text/xml 向后台服务器提交结构化数据(RESTful 设计风格需要)
application/octet-stream(8进制流),如果不想告诉服务器具体的文件类型,可以使用这个 Content-Type
Content-Length: 服务器返回给客户端数据的时候,告诉数据占多少字节
Content-Length: 1000, 数据占1000字节
Content-Type 字段用于服务器回应时,告诉客户端,本次数据是什么格式。(html/json/xml/图片、音频、视频、zip等 )
Content-Type: text/html; charset=utf-8, 发送的是网页,而且编码是UTF-8。
text/plain
image/jpg
image/png
image/gif
text/html
application/json
Content-Encoding 字段说明数据的压缩方法。表示服务器返回的数据使用了什么压缩格式
post/get
get 获取数据
不会修改服务器的资源,所以是安全的。
每次操作的结果都一样,所以是幂等的。
GET请求能够被缓存, 会保存在 Cache 目录中 \bundleId 下 Cache.db 中
cfurl_cache_receiver_data,缓存所有的请求数据
cfurl_cache_response,缓存所有的响应
不能发送敏感数据,请求大小限制在2-8k
URL 字符串中如果包含中文、空格,需要添加百分号转义[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
post 发送数据,并且接收响应,会对服务器的资源有影响,所以是不安全的,
由于每次post 都会创建或者修改资源,所以也不是幂等的。
不能被缓存,发送敏感数据,安全,请求大小依赖于服务器的设置,一般PHP = 2M
上传文件:
请求格式
OC:
Content-Type: multipart/form-data; boundary=boundary
上传的数据格式
//// ------ 单个文件上传 -------
// name 服务器对应的字段名;filename 上传到服务器后的名字
--boundary
Content-Disposition: form-data; name="userfile"; filename="aaa.txt"
Content-Type: application/octet-stream
....要上传文件的二进制数据 ...
--boundary--
//// ------ 多个文件上传 -------
--boundary
Content-Disposition: form-data; name="userfile[]"; filename="aaa.txt"
Content-Type: application/octet-stream
....要上传文件的二进制数据 ...
--boundary
Content-Disposition: form-data; name="userfile[]"; filename="aaa副本.txt"
Content-Type: application/octet-stream
....要上传文件的二进制数据 ...
--boundary
// status 是脚本文件接收参数的名称
Content-Disposition: form-data; name="status"
....要上传文件的二进制数据 ...
--boundary--
上传一个文件:
OC:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"001.png" withExtension:nil];
NSData *data = [NSData dataWithContentsOfURL:fileURL];
[self uploadFile:@"userfile" fileName:@"abc" fileData:data];
}
/// 上传单个文件
///
/// @param fieldName 服务器自短命
/// @param fileName 文件名
/// @param fileData 上传文件二进制数据
- (void)uploadFile:(NSString *)fieldName fileName:(NSString *)fileName fileData:(NSData *)fileData {
// 1. url - 负责上传的脚本
NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload.php"];
// 2. request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSString *typeValue = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:typeValue forHTTPHeaderField:@"Content-Type"];
request.HTTPBody = [self formData:fieldName fileName:fileName fileData:fileData];
// 3. connection
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(@"%@", [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]);
}];
}
/// 生成 formData 二进制数据
///
/// @param fieldName 服务器字段名
/// @param fileName 文件名
/// @param fileData 上传文件二进制数据
///
/// @return formData 二进制数据
- (NSData *)formData:(NSString *)fieldName fileName:(NSString *)fileName fileData:(NSData *)fileData {
NSMutableData *dataM = [NSMutableData data];
// 拼接数据
NSMutableString *strM = [NSMutableString string];
[strM appendFormat:@"--%@\r\n", boundary];
[strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fieldName, fileName];
[strM appendString:@"Content-Type: application/octet-stream\r\n\r\n"];
[dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
[dataM appendData:fileData];
NSString *tail = [NSString stringWithFormat:@"\r\n--%@--", boundary];
[dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];
return dataM.copy;
}
青山不改,绿水长流,后会有期,感谢每一位佳人的支持!