iOS开发基础40-网络编程:HTTP 协议、GET/POST、NSURLConnection 与 NSURLSession

iOS 网络编程深度解析:HTTP 协议、GET/POST、NSURLConnection 与 NSURLSession

本文系统梳理 iOS 网络编程:网络基础概念、URL 结构、HTTP 协议特性、GET 与 POST 对比、HTTP 请求/响应结构、NSURLConnection(已废弃)与 NSURLSession(推荐)的使用,以及常见状态码和 HTTPS 基础。


一、网络基础

1. 为什么学习网络编程

移动互联网时代,几乎所有应用都需要与服务器交换数据实现实时更新:新闻资讯、视频播放、音乐播放、地图导航、电商购物、社交应用等。

2. 基本概念

概念 说明
客户端(Client) 运行在用户设备上的应用(iOS/Android App)
服务器(Server) 提供服务和数据的远程计算机
请求(Request) 客户端向服务器索取/提交数据
响应(Response) 服务器处理请求后返回的数据

3. 服务器类型

  • 远程服务器:上线后的正式服务器,供全体用户使用。
  • 本地服务器:开发测试阶段使用,部署在本地或内网,速度快,便于调试。

二、URL 与协议

1. URL 定义

URL(Uniform Resource Locator,统一资源定位符)用于定位互联网上的唯一资源,客户端通过 URL 找到目标服务器。

2. URL 完整格式

协议://主机地址:端口号/路径?查询参数#片段
组成部分 说明 示例
协议 数据传输方式 https
主机地址 服务器 IP 或域名 api.example.com
端口号 服务端口(可省略,HTTP 默认 80,HTTPS 默认 443) 443
路径 资源在服务器中的位置 /v1/users
查询参数 键值对参数,? 开头,& 分隔 ?page=1&size=20
片段 锚点,# 开头,仅客户端使用 #section1

3. 常见协议

协议 说明 默认端口
HTTP 超文本传输协议,明文传输 80
HTTPS 安全 HTTP,SSL/TLS 加密传输 443
FTP 文件传输协议 21
FILE 本地文件访问 -

HTTP vs HTTPS:HTTPS 在 HTTP 基础上加入 SSL/TLS 加密层,数据传输加密、服务器身份验证(证书)、数据完整性校验,防止窃听和篡改。现代 App 应优先使用 HTTPS,iOS 9+ 的 ATS(App Transport Security)默认禁止明文 HTTP 请求。


三、HTTP 协议

1. HTTP 简介

HTTP(Hypertext Transfer Protocol,超文本传输协议)规定客户端与服务器之间的数据传输格式,是 Web 和移动端最常用的应用层协议。

2. HTTP 特点

  • 简单快速:协议格式简单,通信速度快。
  • 灵活:通过 Content-Type 允许传输各种类型数据(JSON、XML、图片、文件等)。
  • 无状态(Stateless):服务器不保存客户端的状态信息,每次请求相互独立。如需保持状态(如登录态),通过 Cookie/Session/Token 实现。
  • 连接模式
    • HTTP 0.9/1.0:非持续连接,每次请求建立一次 TCP 连接,响应后立即断开。
    • HTTP 1.1:默认持续连接(Keep-Alive),一次 TCP 连接可处理多个请求,减少握手开销。

3. HTTP 通信过程

客户端 ──请求(Request)──▶ 服务器
客户端 ◀──响应(Response)── 服务器

一个完整的 HTTP 通信 = 一个请求 + 一个响应。


四、GET 与 POST

1. HTTP 请求方法

HTTP/1.1 定义了多种请求方法,最常用的是 GET 和 POST:

方法 说明
GET 获取资源(查询、读取)
POST 提交数据(创建、登录)
PUT 更新资源(全量替换)
DELETE 删除资源
PATCH 部分更新
HEAD 获取响应头(无响应体)
OPTIONS 查询服务器支持的方法

RESTful 风格中,GET 查询、POST 创建、PUT 更新、DELETE 删除,语义清晰。

2. GET 与 POST 对比

对比项 GET POST
参数位置 附加在 URL 之后(?key=value 放在请求体(Body)中
数据可见性 参数在 URL 中可见 参数不可见(但并非加密,抓包仍可看到)
数据量限制 受浏览器和服务器 URL 长度限制(非 HTTP 协议限制) 通常无严格限制(服务器可配置上限)
缓存 可被浏览器缓存 默认不缓存
书签/历史 可收藏为书签、保留在历史记录 不可
适用场景 查询、获取数据 提交、创建、敏感数据

关于 GET 参数长度限制:HTTP 协议本身没有规定 URL 长度上限,限制来自具体的浏览器和服务器实现。例如旧版 IE 限制约 2083 字符,Apache 默认限制约 8192 字符。因此"GET 参数不能超过 1KB"的说法不准确,实际限制因环境而异,但 GET 不适合传输大量数据。

3. GET 与 POST 选择

  • 查询/获取数据 → GET
  • 提交/创建数据 → POST
  • 大量数据 → POST
  • 敏感信息(密码、Token) → POST(配合 HTTPS 加密)
  • RESTful 更新 → PUT,删除 → DELETE

五、iOS 网络请求方案

1. 苹果原生方案

方案 说明 状态
NSURLConnection 早期网络 API,同步/异步/代理 iOS 9 起废弃
NSURLSession 功能强大,支持后台下载/上传、任务管理 推荐
CFNetwork 底层 C 语言网络接口 底层定制

2. 第三方框架

框架 说明
AFNetworking Objective-C 最常用网络库,基于 NSURLSession 封装
Alamofire AFNetworking 的 Swift 版本
MKNetworkKit 轻量网络库,使用者较少

3. 建议

新项目推荐使用 NSURLSession(苹果原生)或 AFNetworking/Alamofire(第三方封装,简化代码)。


六、HTTP 请求与响应结构

1. HTTP 请求

一个完整的 HTTP 请求包含:

请求行(方法 + 路径 + HTTP 版本)
请求头(Key: Value,多行)
空行
请求体(Body,POST/PUT 才有)

示例:

POST /login HTTP/1.1
Host: api.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
User-Agent: MyApp/1.0

username=test&pwd=password

常见请求头:

请求头 说明
Host 服务器域名
Content-Type 请求体数据类型(application/jsonmultipart/form-data 等)
Content-Length 请求体长度
User-Agent 客户端标识
Authorization 认证信息(Token)
Accept 客户端可接受的响应类型
Cookie 客户端携带的 Cookie

2. HTTP 响应

一个完整的 HTTP 响应包含:

状态行(HTTP 版本 + 状态码 + 状态描述)
响应头(Key: Value,多行)
空行
响应体(Body,服务器返回的数据)

示例:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 42
Server: nginx

{"code":0,"message":"success","data":{}}

常见响应头:

响应头 说明
Content-Type 响应体数据类型
Content-Length 响应体长度
Server 服务器类型
Set-Cookie 设置 Cookie
Location 重定向目标 URL(3xx 状态码)
Cache-Control 缓存控制

七、NSURLConnection(已废弃,了解)

NSURLConnection 是 iOS 早期的网络 API,iOS 9 起被 NSURLSession 取代,新项目不推荐使用。

1. 常用类

说明
NSURL 请求地址
NSURLRequest 请求对象(不可变)
NSMutableURLRequest 可变请求对象
NSURLConnection 发送请求、建立连接、处理响应

2. 同步请求(阻塞当前线程)

NSURL *url = [NSURL URLWithString:@"http://example.com/data"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
                                      returningResponse:&response
                                                  error:&error];

同步请求会阻塞当前线程,禁止在主线程调用,否则 UI 卡死。

3. 异步请求(Block 回调)

NSURL *url = [NSURL URLWithString:@"http://example.com/data"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    if (!connectionError && data) {
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@", result);
    }
}];

4. 代理方式

@interface ViewController () <NSURLConnectionDataDelegate>
@property (nonatomic, strong) NSMutableData *responseData;
@end

@implementation ViewController

- (void)startRequest {
    NSURL *url = [NSURL URLWithString:@"http://example.com/data"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    self.responseData = [NSMutableData data];
    [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

// 接收到服务器响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [self.responseData setLength:0];
}

// 接收到数据(可能调用多次,需拼接)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.responseData appendData:data];
}

// 请求完成
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSString *result = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
    NSLog(@"%@", result);
}

// 请求出错
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"错误: %@", error);
}

@end

5. NSMutableURLRequest 常用设置

NSURL *url = [NSURL URLWithString:@"http://example.com/login"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";                                    // 请求方法
request.HTTPBody = [@"username=test&pwd=123" dataUsingEncoding:NSUTF8StringEncoding]; // 请求体
request.timeoutInterval = 15;                                    // 超时时间(秒)
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; // 请求头
[request setValue:@"Bearer token123" forHTTPHeaderField:@"Authorization"];

6. GET 请求创建

NSString *urlStr = @"http://example.com/search?keyword=hello&page=1";
// URL 编码(处理中文、特殊字符)
// stringByAddingPercentEscapesUsingEncoding 已废弃,改用:
urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *request = [NSURLRequest requestWithURL:url];

stringByAddingPercentEscapesUsingEncoding: 在 iOS 9 已废弃,应使用 stringByAddingPercentEncodingWithAllowedCharacters:


八、NSURLSession(推荐)

NSURLSession 是 iOS 7+ 引入的现代网络 API,取代 NSURLConnection,支持后台下载/上传、任务管理、配置灵活。

1. 基本使用(Data Task)

// 获取共享 session(基本配置)
NSURLSession *session = [NSURLSession sharedSession];

NSURL *url = [NSURL URLWithString:@"https://api.example.com/data"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];

// 创建数据任务
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                          completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (error) {
        NSLog(@"请求失败: %@", error);
        return;
    }
    // 解析响应数据(在子线程执行,更新 UI 需回主线程)
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"结果: %@", json);
    });
}];

[task resume]; // 任务默认挂起,必须 resume 才开始

2. POST 请求(JSON)

NSURL *url = [NSURL URLWithString:@"https://api.example.com/login"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

NSDictionary *params = @{@"username": @"test", @"pwd": @"123"};
request.HTTPBody = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil];

NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request
                                                                 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    // 处理响应
}];
[task resume];

3. 自定义 Session 配置

// 默认配置(类似 sharedSession,但可自定义)
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.timeoutIntervalForRequest = 15;       // 请求超时
config.timeoutIntervalForResource = 30;      // 资源超时
config.HTTPAdditionalHeaders = @{@"User-Agent": @"MyApp/1.0"}; // 额外请求头

NSURLSession *session = [NSURLSession sessionWithConfiguration:config
                                                        delegate:self
                                                   delegateQueue:[NSOperationQueue mainQueue]];

4. 下载任务(Download Task)

NSURL *url = [NSURL URLWithString:@"https://example.com/file.zip"];
NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithURL:url
                                                                   completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
    // location 是临时文件路径,需移动到目标位置
    NSString *dest = [NSTemporaryDirectory() stringByAppendingPathComponent:@"file.zip"];
    [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:dest] error:nil];
}];
[task resume];

NSURLSession 任务(DataTask/DownloadTask/UploadTask)创建后默认挂起,必须调用 resume 才开始执行。可调用 suspend 暂停、cancel 取消。


九、HTTP 状态码

状态码 类别 说明
200 2xx 成功 请求成功
201 2xx 成功 已创建(资源创建成功)
204 2xx 成功 无内容(成功但无响应体)
301 3xx 重定向 永久重定向
302 3xx 重定向 临时重定向
304 3xx 重定向 未修改(使用缓存)
400 4xx 客户端错误 请求参数错误
401 4xx 客户端错误 未授权(未登录/Token 失效)
403 4xx 客户端错误 禁止访问(无权限)
404 4xx 客户端错误 资源未找到
405 4xx 客户端错误 方法不允许
500 5xx 服务器错误 服务器内部错误
502 5xx 服务器错误 错误网关
503 5xx 服务器错误 服务不可用
504 5xx 服务器错误 网关超时

十、Swift 版本对照

NSURLSession(Swift)

// GET 请求
let url = URL(string: "https://api.example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error {
        print("请求失败: \(error)")
        return
    }
    guard let data = data else { return }
    do {
        let json = try JSONSerialization.jsonObject(with: data)
        DispatchQueue.main.async {
            print("结果: \(json)")
        }
    } catch {
        print("解析失败: \(error)")
    }
}
task.resume() // 必须 resume

// POST 请求(JSON)
var request = URLRequest(url: URL(string: "https://api.example.com/login")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: ["username": "test", "pwd": "123"])

URLSession.shared.dataTask(with: request) { data, _, error in
    // 处理响应
}.resume()

// 下载任务
let downloadURL = URL(string: "https://example.com/file.zip")!
URLSession.shared.downloadTask(with: downloadURL) { location, _, error in
    guard let location = location else { return }
    let dest = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("file.zip")
    try? FileManager.default.moveItem(at: location, to: dest)
}.resume()

URL 编码

let urlStr = "https://example.com/search?keyword=你好"
let encoded = urlStr.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let url = URL(string: encoded!)

十一、总结

  • 网络基础:客户端发送请求、服务器返回响应;远程服务器用于生产,本地服务器用于开发测试。
  • URL:格式为 协议://主机:端口/路径?参数#片段,HTTP 默认端口 80,HTTPS 默认 443;HTTPS 在 HTTP 基础上加密传输,iOS ATS 默认禁止明文 HTTP。
  • HTTP 协议:简单快速、灵活、无状态;HTTP 1.1 默认持续连接(Keep-Alive);通信过程 = 请求 + 响应。
  • GET vs POST:GET 参数在 URL(可见、受 URL 长度限制、可缓存),POST 参数在请求体(不可见、数据量大、不缓存);HTTP 协议本身无 URL 长度限制,限制来自浏览器/服务器;查询用 GET,提交用 POST,RESTful 中 PUT 更新、DELETE 删除。
  • 请求/响应结构:请求 = 请求行 + 请求头 + 空行 + 请求体;响应 = 状态行 + 响应头 + 空行 + 响应体。
  • NSURLConnection:iOS 早期 API,iOS 9 起废弃;支持同步(阻塞)、异步(Block)、代理三种方式;同步请求禁止在主线程调用。
  • NSURLSession:iOS 7+ 推荐 API,取代 NSURLConnection;支持 DataTask(普通请求)、DownloadTask(下载)、UploadTask(上传)、后台会话;任务创建后默认挂起,必须 resume 才执行;可自定义超时、请求头、代理。
  • 状态码:2xx 成功、3xx 重定向、4xx 客户端错误、401 未授权、403 禁止、404 未找到、5xx 服务器错误。
  • URL 编码stringByAddingPercentEscapesUsingEncoding: 已废弃,改用 stringByAddingPercentEncodingWithAllowedCharacters:(OC)/ addingPercentEncoding(withAllowedCharacters:)(Swift)。

posted @ 2015-08-21 22:01  Mr.陳  阅读(2011)  评论(0)    收藏  举报