谈谈移动开发中必须要知道的网络知识

本文Demo的完整工程代码, 客户端基于iOS实现, 参考这里的StudyHTTP, 服务器基于node.js实现, 参考这里的StudyHTTP

目录

  • URI, URL和URN

    • 定义

    • 关系和区别

  • RESTful-API

    • 什么是RESTful-API?

    • RESTful-API有哪些特点?

  • HTTP-Header

    • Accept-Encoding

    • Content-Type

    • Range

    • User-Agent

  • HTTP-Status-Code

    • 2XX-成功状态码-请求正常处理完毕

    • 3XX-重定向状态码-需要进行附加操作以完成请求

    • 4XX-客户端错误状态码-服务器无法处理请求

    • 5XX-服务器错误状态码-服务器处理请求出错

  • HTTP数据传递

    • GET方式的参数会添加到URL中

    • POST方式的参数会添加到body中

  • HTTPS

URI, URL和URN

定义

URI(Uniform Resource Identifier, 统一资源标识符)用来唯一的标识一个资源

URL(Uniform Resource Locator, 统一资源定位器)可以用来标识一个资源, 而且还指明了如何locate这个资源

URN(Uniform Resource name, 统一资源命名)是通过名字来标识资源

关系和区别

  • URL和URN都是一种URL
谈谈移动开发中必须要知道的网络知识_第1张图片
mobile-development-http_01.jpg
  • URI是以一种抽象的, 高层次概念定义统一资源标识, 而URL和URN则是具体的资源标识的方式

  • URI可以是绝对的也可以是相对的, 而URL则必须提供足够的信息来定位

更多可以参考你知道URL、URI和URN三者之间的区别吗?, URI和URL的区别, URI 和 URL的区别

RESTful API

什么是RESTful API?

首先要搞清楚什么是REST

REST(Representational State Transfer, 表现层状态转化)是一种网络架构规范

知道什么是REST, 就知道了什么是RESTful API

实现了REST规范的Web API就叫RESTful API

RESTful API有哪些特点?

  • 总是使用HTTPS

或许这不属于REST架构, 但是却是最最重要和基础的一点, 详细可以参考本文的这一章HTTPS

  • 将API的版本号放入URL
https://api.example.com/v1/
  • 每个网址代表一种资源

所以网址中不能有动词, 只能有名词, 且使用复数

https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees
  • HTTP动词对应资源的具体操作类型
GET(SELECT) 从服务器取出资源(一项或多项) 
POST(CREATE) 在服务器新建一个资源
PUT(UPDATE) 在服务器更新资源(客户端提供改变后的完整资源) 
PATCH(UPDATE) 在服务器更新资源(客户端提供改变的属性) 
DELETE(DELETE) 从服务器删除资源

例子如下

GET /zoos 列出所有动物园
POST /zoos 新建一个动物园
GET /zoos/ID 获取某个指定动物园的信息
PUT /zoos/ID 更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID 更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID 删除某个动物园

更多RESTful API, 请参考RESTful API 设计指南

HTTP Header

Accept-Encoding

  • gzip - 使用gzip(GNU zip)压缩

  • compress - 使用Unix compress压缩

  • deflate - 使用zlib压缩

  • identity - 不进行编码

服务器开启压缩可以提高传输的效率, 详细可以参考expressjs/compression

Content-Type

常见的Content-Type有

  • application/json

  • text/json

application/json和text/json都是指json格式, 前者是官方规范, 后者是为了兼容, 详细参考What is the exact difference between content-type: text/json and application/json?

  • text/xml

  • text/html

  • text/plain

  • multipart/form-data

multipart/form-data用于POST上传文件时, 同时还需要设置boundary字段

在iOS开发中最有名的网络库AFNetworking中

  • request serializers支持的Content-Type分别是

(1) AFJSONRequestSerializer

[mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

(2) AFPropertyListRequestSerializer

[mutableRequest setValue:@"application/x-plist" forHTTPHeaderField:@"Content-Type"];

(3) AFHTTPRequestSerializer

application/x-www-form-urlencoded

(4) AFStreamingMultipartFormData

[self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", self.boundary] forHTTPHeaderField:@"Content-Type"];
  • response serializers支持的Content-Type分别是

(1) AFJSONResponseSerializer

self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];

(2) AFXMLParserResponseSerializer

self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/xml", @"text/xml", nil];

(3) AFXMLDocumentResponseSerializer

self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/xml", @"text/xml", nil];

(4) AFPropertyListResponseSerializer

self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/x-plist", nil];

(5) AFImageResponseSerializer

self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil];

例如

在使用AFHTTPSessionManager的类构造方法+ (instancetype)manager生成对象时, 由于response serializer默认是AFJSONResponseSerializer

self.responseSerializer = [AFJSONResponseSerializer serializer];

如果response的Content-Type不是json类型的话, 那么就会出现类似下面的错误

2016-09-21 14:22:37.246 StudyHTTP[7589:623717] error = Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: text/html" UserInfo={com.alamofire.serialization.response.error.response= { URL: http://localhost:3000/users/ } { status code: 200, headers {
    Connection = "keep-alive";
    "Content-Length" = 23;
    "Content-Type" = "text/html; charset=utf-8";
    Date = "Wed, 21 Sep 2016 06:22:35 GMT";
    Etag = "W/\"17-i6pE/Ux9hQaoN6ksprpWig\"";
    "Proxy-Connection" = "Keep-alive";
    "X-Powered-By" = Express;
} }, NSErrorFailingURLKey=http://localhost:3000/users/, com.alamofire.serialization.response.error.data=<72657370 6f6e6420 77697468 20612072 65736f75 726365>, NSLocalizedDescription=Request failed: unacceptable content-type: text/html}

Range

对于只需获取部分资源的范围请求, 包含首部字段Range即可告知服务器资源的指定范围

使用这个字段就可以实现文件的断点续传

User-Agent

将创建请求的浏览器和用户代理名称等信息传达给服务器

例如

当使用Safari浏览打开百度时

User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Safari/602.1.50

关于更多Content-Type, 可以参考常用对照表 HTTP Content-type

HTTP Status Code

2XX 成功状态码 请求正常处理完毕

200 OK

201 Created

202 Accepted

204 No Content

206 Partial Content

3XX 重定向状态码 需要进行附加操作以完成请求

301 Moved Permanently(永久重定向)

302 Found(临时重定向)

4XX 客户端错误状态码 服务器无法处理请求

400 Bad Request

401 Unauthorized

403 Forbidden

404 Not Found

5XX 服务器错误状态码 服务器处理请求出错

500 Internal Server Error

502 Bad Gateway

503 Service Unavailable

更多参考10 Status Code Definitions

HTTP数据传递

GET方式的参数会添加到URL中

例如URL请求和参数设置如下(实现基于iOSAFNetworking)

[self.sessionManager GET:@"http://localhost:3000/users/" parameters:@{@"key": @"value"} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    NSLog(@"responseObject = %@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSLog(@"error = %@", error);
}];

那么HTTP请求实际的URL是

http://localhost:3000/users/?key=value

这时, 服务器通过request的query取出数据

console.log(req.query); // { key: 'value' }

POST方式的参数会添加到body中

例如URL请求和参数设置如下(实现基于iOSAFNetworking)

[self.sessionManager POST:@"http://localhost:3000/users/" parameters:@{@"key": @"value"} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    NSLog(@"responseObject = %@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSLog(@"error = %@", error);
}];

此时HTTP请求的body就是

key=value

这时, 服务器通过request的body取出数据

console.log(req.body); // { key: 'value' }

HTTPS

发展至今, HTTPS已经可以算是标配了, 当然中国的网络环境总是"慢人一步", 为什么要如此重视HTTPS呢?

这是因为HTTP存在以下问题

  • 通信使用明文(不加密), 内容可能会被窃听

  • 不验证通信方的身份, 因此有可能遭遇伪装

  • 无法证明报文的完整性, 所以有可能已遭篡改

而HTTP加上加密处理和认证以及完整性保护后即是HTTPS

简单来说HTTPS(HTTP secure) = HTTP + 加密 + 认证 + 完整性保护

至于HTTPS为什么安全的具体分析, 可以参考SSL/TLS协议运行机制的概述

这里总结下HTTPS与HTTP的几个明显差异

  • HTTPS = HTTP over SSL/TLS (其中: SSL是Secure Sockets Layer的缩写, TLS是Transport Layer Security的缩写)

  • HTTPS需要到CA(Certificate Authority)申请证书

  • HTTP默认采用80端口, 而HTTPS默认采用443端口

HTTPS的简单流程是这样子的

  • 客户端向服务器端索要并验证公钥

  • 双方协商生成"对话密钥"

  • 双方采用"对话密钥"进行加密通信

详细的过程可以参考图解SSL/TLS协议

参考

  • 图灵程序设计丛书:图解HTTP

  • 怎样用通俗的语言解释什么叫 REST,以及什么是 RESTful?

  • HTTPS 升级指南

  • HTTPS为什么安全 &分析 HTTPS 连接建立全过程

更多文章, 请支持我的个人博客

你可能感兴趣的:(谈谈移动开发中必须要知道的网络知识)