美文网首页
ios随笔学习之HTTP基础

ios随笔学习之HTTP基础

作者: 冷武橘 | 来源:发表于2020-12-17 18:18 被阅读0次

    一、URL的编码

    URL中一旦出现了特殊字符(比如中文、空格),需要进行编码。
    比如:

    编码前:https://www.baidu.com/s?wd=百度
    编码后:https://www.baidu.com/s?wd=%E5%8D%8E%E4%B8%BA
    
    • 0、URL的组成?参考iOS官方文档 Foundation篇---URLs
    • 1、为什么要编码? 参考浅析URL编码
    • 2、ios编码方法参考iOS的URL编码
    • 3、post请求一般不需要,将一些特殊字符参数放在请求体内不会有什么解析歧义。自然发送get请求、webview加载一个请求时出现特殊字符时需要。

    二、请求头和响应头

    2.1、请求头字段

    有关要获取的资源或客户端本身消息的消息头

    一个ios程序代码示例:

        NSString *urlString = @"http://testct.56cold.com/wechat/user/login”;
        NSURL *url = [NSURL URLWithString:urlString];
         NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        request.HTTPMethod = @“POST”;
        NSString *str = [NSString stringWithFormat:@"username=1e00000000&password=666e66”];
        request.HTTPBody = [str dataUsingEncoding:NSUTF8StringEncoding];
         NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
         NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
         NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
         [task resume];
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
    didCompleteWithError:(nullable NSError *)error{
        NSLog(@"请求完成或者是失败%@",error);  NSLog(@"%@",task.currentRequest.allHTTPHeaderFields);
    }
    

    控制台打印:


    截屏2020-12-16 上午10.45.10.png

    青花瓷抓包截图:


    截屏2020-12-16 上午10.53.55.png
    字段名 说明 示例
    User-Agent 客户端的身份标识 444/1/CFNetwork/1209Darwin/20.2.0
    Host 服务器的域名、端口号 testct.56cold.com
    Accept-Charset 能够接受的字符集 GB2312,utf-8;q=0.7, *;q=0.7
    Accept-Encoding 能够接受的编码方式列表 gzip, deflate
    Accept-Language 能够接受的响应内容的自然语言列表 en-us
    Content-Length 求体的长度(字节为单位) 36
    Content-Type 请求体的类型 application/x-www-form-urlencoded
    Connection 客户端想要优先使用的连接类型 keep-alive
    Accept 能够接受的响应内容类型 text/plain
    Range 仅请求某个实体的一部分。字节偏移以 开始 bytes=500-599
    Cookie 之前由服务器通过Set-Cookies发送的cookies

    2.1.2、Accept

    用来告知(服务器)客户端可以处理的内容类型,这种内容类型用MIME类型来表示。借助内容协商机制, 服务器可以从诸多备选项中选择一项进行应用,并使用 Content-Type 应答头通知客户端它的选择。浏览器会基于请求的上下文来为这个请求头设置合适的值

    • Accept: text/html

    • Accept: image/*

    • Accept: text/html, application/xhtml+xml, application/xml;q=0.9, /;q=0.8

    • Accept:*/: 接受任何类型的数据
      对于ios原生CFNetwork请求默认是Accept:*/
      ,接受任何类型的数据。

    2.1.3、Content-Type

    告诉服务器所发送数据的类型,这样服务端就知道如何去处理收到的数据。比如application/json,代表发送端发送的数据格式是json.

    • 1、application/x-www-form-urlencode
      一般是默认的请求数据编码形式。用&分隔参数,用=分隔键和值,字符用URL编码方式进行编码。比如:username=18500000&password=66666
      [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type”];
      回忆一下get请求数据的传递也是这种编码方式。
      NSString *urlString = @"http://tstt.56cold.com/wechat/user/login?username=18500000000&password=666666”;
    • 2、 application/json

    请求数据编码形式是序列化的JSON字符串{"username":"18500000000","password":”666666”}
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type”];
    注意:我们在编码时传递数据时,必须根据设置的Content-Type去处理请求体的数据,如果说你设置了application/json,你就不能随意的
    NSString *str = [NSString stringWithFormat:@"username=18500000000&password=666666”]; request.HTTPBody = [str dataUsingEncoding:NSUTF8StringEncoding]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type”];像这样硬生生的传递了application/x-www-form-urlencode的编码格式,这样服务器肯定会给你报参数错误

    AFN设置请求体:
    NSString *URLString = @"http://testct.56locold.com/wechat/user/login”;
    NSDictionary *parameters = @{@"username": @"18500000000", @"password": @"666666”};
    1、URL Form Parameter Encoding(application/x-www-form-urlencode)

        AFHTTPSessionManager *manger=[AFHTTPSessionManager manager];
        manger.requestSerializer = [AFHTTPRequestSerializer serializer];
        [manger POST:URLString parameters:parameters headers:nil progress:nil success:nil failure:nil];
        
    

    2、JSON Parameter Encoding(application/json)

        AFHTTPSessionManager *manger=[AFHTTPSessionManager manager];
        manger.requestSerializer = [AFJSONRequestSerializer serializer];
        [manger POST:URLString parameters:parameters headers:nil progress:nil success:nil failure:nil];
    
    • 3、multipart/form-data
      文件上传时,必须使用的文件编码格式
      [request setValue:@"multipart/form-data; boundary=分割线" forHTTPHeaderField:@"Content-Type”];
      必须设置这样的请求头,才能进行文件上传。
        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        NSDictionary *dict = @{
                               @"username":@“abcdef”
                               };
        [manager POST:@"http://120.25.226.186:32812/upload" parameters:dict constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
           NSData *imageData = [NSData dataWithContentsOfFile:@"/Users/xiaomage/Desktop/Snip20161127_246.png”];
            
            //处理要上传的文件
            /* 参数说明
             *
             * 第一个参数:要上传文件的二进制数据
             * 第二个参数:具体参数值file。  和username一样,去作为一个key,服务器规定的。一般写”file”
             * 第三个参数:文件的名称
             * 第四个参数:文件的二进制数据类型
             */
            [formData appendPartWithFileData:imageData name:@"file" fileName:@"123.png" mimeType:@"image/png”];
        } progress:nil success:nil failure:nil];
    
    • 4、补充
      作为一个ios开发者,你可能会听到别人form表单提交、表单提交,这是千万别慌。form表单其实是就是一个html标签,经常会用来提交网络请求的,仅此而已。你不要误以为表单提交是另一种什么的网编码技术。下面是一个html的form表单示例,enctype属性是设置请求体的数据格式
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8"><title>Title</title></head>
    <body>
     <form  action="http://testct.56cold.com/wechat/user/login"   enctype="application/x-www-form-urlencoded" method=“post”>
         <div>
             <label for="name">用户名:</label>
             <input type="text" id="name" name="username” />
         </div>
         <div>
             <label for="passwd">密码:</label>
             <input type="password" id="passwd" name="password” />
         </div>
         <div>
             <input type="submit" id="submit" name="submit_button" value="提交” />
         </div>
     </form>
    </body>
    </html>
    

    2.1.4、Range

    如果想进行断点下载,我们需要在请求头中设置文件下载的range,告诉服务器,我们需要从文件的哪个位置开始下载。
    [request setValue:@"bytes=0-499" forHTTPHeaderField:@"Range”];

    • Range: bytes=0-499 , 表示头500个字节
    • Range: bytes=500-999 , 表示第二个500字节
    • Range: bytes=-500, 表示最后500个字节
    • Range: bytes=500- ,表示500字节以后的范围

    2.1.5、Cookie

    • cookie:HTTP Cookie是服务器发送到客户端并保存在本地的一小块数据,它会在客户端下一次向同一服务器再发起请求时被携带并发送到服务器上,以此来维护弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。

    • session: Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
      session也是基于cookie进行的,可以说session是另一种cookie

    当客户端访问服务器,Service响应后会通过request.getSession()获得一个session对象(如果request没有带JSESSIONID,就会创建新的Session对象;如果request带了JSESSIONID,就会返回对应的Session对象)

        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String username = request.getParameter("username”);
            String password = request.getParameter("password”);
            response.setContentType("text/html; charset=UTF-8”);
                // 将用户信息存放到Session中
          HttpSession session = request.getSession();
          session.setAttribute("username", username);
           session.setAttribute("password", password);
    }
    

    当Service返回数据时,Set-Cookie:JSESSIONID=666会自动添加到响应头上。当客户端再次访问服务器时,客户端也会自动将Cookie:SESSIONID=666携带到请求头上。
    现在的http会话都是通过session这样的机制维持状态的,我们这里所说的cookie也就是session-cookie

    三、响应头字段

    字段 说明 示例
    Server 服务器的名字 Apache/2.4.1(unix)
    Date 发送消息的日期和时间 Date: Tue,15 Nov 1994 08:12:31 GMT
    Content-Type 响应体的类型 text/html;charset=utf-8
    Content-Encoding 内容所使用的编码类型 gzip
    Content-Length 响应体的长度(字节为单位) 348
    Content-Disposition 一个可以让客户端下载文件并建议文件名的头部 attachment;filename=“name.text”
    Content-Range 这条消息是属于完整消息的哪一部分 bytes 21010-47021/47022
    Last-Modified 所请求的对象的最后修改时间 Tue,15 Nov 1994 12:45:26 GMT
    Set-Cookie 返回一个Cookie让客户端保存
    Access-Control-Allow-Origin 指定哪些网站可参与到跨来源资源共享过程中 *
    Location 用来进行重定向,或者在创建了某个新资源时使用 http://www.w3.org

    3.1、重定向

    URL 重定向,也称为 URL 转发,是一种当实际资源,如单个页面、表单或者整个 Web 应用被迁移到新的 URL 下的时候,保持(原有)链接可用的技术。HTTP 协议提供了一种特殊形式的响应—— HTTP 重定向(HTTP redirects)来执行此类操作。
    通俗地来讲:例如浏览器想要访问http://s.click.taobao.com页面,然而服务器却又返回了https://error.taobao.com/app/tbhome/common/error.html,最终显示了error.html内容

    截屏2020-12-21 下午1.55.32.png
        NSString *urlString = @"http://s.click.taobao.com”;
        NSURL *url = [NSURL URLWithString:urlString];
         NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
         NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
         NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
         NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
        [task resume];
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
    didCompleteWithError:(nullable NSError *)error{
        NSHTTPURLResponse *respons = (NSHTTPURLResponse *)task.response;
        NSLog(@"%@",respons.allHeaderFields);
        NSLog(@"%ld",(long)respons.statusCode);
        NSLog(@"原始请求:%@",task.originalRequest.URL);
        NSLog(@"现在的请求:%@",task.currentRequest.URL);
    }
    

    原始请求:http://s.click.taobao.com。现在的请求:https://error.taobao.com/app/tbhome/common/error.htm,状态码200,请求头并没返回location。要想监听到重定向应该在下面这个方法:

    //#pragma mark - 即将重定向时调用
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                         willPerformHTTPRedirection:(NSHTTPURLResponse *)response
                                         newRequest:(NSURLRequest *)request
     completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler{
      NSLog(@"原始请求:%@",task.currentRequest.URL);
        completionHandler(request);
        NSLog(@"%@",task.currentRequest.allHTTPHeaderFields);
        NSLog(@"%@",response.allHeaderFields);
      
        NSLog(@"重定向的请求:%@",request.URL);
        NSLog(@"即将重定向时调用”);
        NSLog(@"%ld",(long)response.statusCode);
    }
    
    截屏2020-12-21 下午2.58.58.png

    原始请求:http://s.click.taobao.com/
    重定向的请求:https://error.taobao.com/app/tbhome/common/error.htm
    状态码:302
    状态码302:请求的资源被暂时的移动到了由Location头部指定的URL上

    wkwebview监听重定向的代理方法:

    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation{
        NSLog(@"原始的url:%@",self.request.URL);
        NSLog(@"发生重定向了的url:%@",webView.URL);
    }
    

    只要服务端response的location设置了url,客户端就会发生重定向

    四、常见的状态码

    状态码可以分为5类
    - 1、信息响应:100~199
    - 2、成功响应:200~299
    - 3、重定向:300~399
    - 4、客户端错误:400~499
    - 5、服务器错误 :500~599

    • 200 OK:请求成功
    • 302 Found:请求的资源被暂时的移动到了由Location头部指定的URL上
    • 304 Not Modified:说明无需再次传输请求的内容,也就是说可以使用缓存的内容
    • 400 Bad Request:由于语法无效,服务器无法理解该请求
    • 401 Unauthorized:由于缺乏目标资源要求的身份验证凭证
    • 403 Forbidden:服务器端有能力处理该请求,但是拒绝授权访问
    • 404 Not Found:服务器端无法找到所请求的资源
    • 405 Method Not Allowed:服务器禁止了使用当前HTTP方法的请求
    • 406 Not Acceptable:服务器端无法提供与Accept-Charset以及Accept-Language指定的值相匹配的响应
    • 408 Request Timeout:服务器想要将没有在使用的连接关闭
    • 500 Internal Server Error:所请求的服务器遇到意外的情况并阻止其执行请求
    • 501 Not Implemented:请求的方法不被服务器支持,因此无法被处理。
      服务器必须支持的方法(即不会返回这个状态码的方法)只有 GET 和 HEAD
    • 502 Bad Gateway:作为网关或代理角色的服务器,从上游服务器(如tomcat)中接收到的响应是无效的
    • 503 Service Unavailable:服务器尚未处于可以接受请求的状态
      通常造成这种情况的原因是由于服务器停机维护或者已超载

    相关文章

      网友评论

          本文标题:ios随笔学习之HTTP基础

          本文链接:https://www.haomeiwen.com/subject/orhwgktx.html