4g请求网页乱码 ios_ios get请求汉字乱码 - CSDN
精华内容
参与话题
  • 客户端:client 服务器:server 请求:request 响应:response 过程 客户端 -> 发送请求 -> 服务器(连接数据库) ...iOS,Android 后端(后台) 服务器 语言:Java、PHP、.NET(主流) 远程服务器-面向所有用户(上线)

    基本概念

    * 客户端:client
    * 服务器:server
    * 请求:request
    * 响应:response
    * 过程
        * 客户端 -> 发送请求 -> 服务器(连接数据库)
        * 服务器 -> 发送响应 -> 客户端
    * 客户端(移动端)
        * 前段(前台)
        * iOS,Android
    * 服务器(后端)
        * 后台
        * Java、PHP、.NET
        * 远程服务器-面向所有用户(上线)
        * 本地服务器-面向公司内部(测试)
    * URL
        * URL的全称是Uniform Resource Locator(统一资源定位符)
        * 通过1个URL,能找到互联网上唯一的1个资源
        * URL就是资源的地址、位置,互联网上的每个资源都有一个唯一的URL
        * URL的基本格式 = 协议://主机地址/路径
    * URL中常见协议
        * HTTP - 网络所有资源(http://)这个最常用
        * file - 本机资源(file://)
        * mailto - 邮件地址 (mailto:)
        * FTP - 网络文件资源 (ftp://)

    HTTP通信

    * http的作用是统一客户端和服务器的数据交换格式,使得彼此可以理解。
    * 优点
         * 简单快速,服务器规模小,通信速度快
         * 灵活,允许传输任意类型的数据
         * HTTP 0.9和1.0使用短连接方式(非持续连接):每次连接只处理一个请求,服务器做出响应后,马上断开连接。

    iOS中常用的HTTP请求方式

    * 原生
         * NSURLConnection - 最古老的方案
         * NSURLSession       - iOS7推出的新技术
         * CFNetworking         - NSURL的底层,纯C语言
    * 第三方框架
         * ASIHttpRequest      - 外号“HTTP终结者”,功能强大,可惜已经停止更新
         * AFNetworking         - 维护使用者多
         * MKNetworkKit        - 印度,维护使用者少
    * HTTP 请求
         * HTTP/1.1 中定义了8种方法
         * GETPOST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
         * 最常用的就是GET、POST

    HTTP 实践 - NSURLConnection(了解即可)

    * HTTP同步请求
    // 发送同步请求,会一直等待, 直到接收到数据
    - (void)requestSynch{
        // 1 创建请求连接
        NSURL *url = [NSURL URLWithString:@"http://www.lala.com/login?username=123&pwd=123"];
        // 2 创建请求
        NSURLRequest *request = [NSURLRequest requestWithURL:url ];
        NSHTTPURLResponse *response = nil;
        NSError *error = nil;
        // 3 发送同步请求
        // endSynchronousRequest阻塞式的方法,等待服务器返回数据
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
        // 4.解析服务器返回的数据(解析成字符串)
        NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"--%@--%@-- %zd",str,response.allHeaderFields,response.statusCode);
    }
    * HTTP异步请求
    // 发送异步请求
    - (void)requestAsync{
        // 1 创建请求连接
        NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=123"];
        // 2 创建请求
        NSURLRequest *request = [NSURLRequest requestWithURL:url ];
        // 3 发送异步请求
        [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            // 4.解析服务器返回的数据(解析成字符串)
            NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSHTTPURLResponse *httpRes = (NSHTTPURLResponse* )response;
            NSLog(@"--%@--%zd--%@--",str,httpRes.statusCode,httpRes.allHeaderFields);
        }];
    }
    * HTTP代理请求模式
         * 协议:NSURLConnectionDataDelegate
         * 实现方法      
    // 1 创建请求连接
        NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=520it&pwd=520it"];
        // 2 创建请求
        NSURLRequest *request = [NSURLRequest requestWithURL:url ];
        // 3 代理请求模式,要遵守协议并实现代理方法
        [NSURLConnection connectionWithRequest:request delegate:self];
    
    ///-----------------------------------------------------------------///
    // 常用代理方法
    // 接收服务器响应
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
        self.localData = [NSMutableData data];
         NSLog(@"-didReceiveResponse-%zd",((NSHTTPURLResponse *)response).statusCode);
    }
    // 接收到服务器的数据(如果数据量比较大,这个方法会被调用多次)
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
        [self.localData appendData:data];
          NSLog(@"-didReceiveData-");
    }
    // 完成数据下载
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
        NSString *str = [[NSString alloc] initWithData:self.localData encoding:NSUTF8StringEncoding];
        NSLog(@"-connectionDidFinishLoading-%@",str);
    }
    // 请求失败:请求超时等
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
         NSLog(@"-didFailWithError-");
    }

    简单登陆界面

    * GET请求
    - (IBAction)loginBtn:(id)sender {
        // 获取控件数据和网络数据进行比对
        NSString *userName = self.userText.text;
        if (userName.length == 0 ) {
            [SVProgressHUD showErrorWithStatus:@"用户名不能为空"];
            return;
        }
        NSString *pwd = self.pwdText.text;
        if (pwd.length == 0) {
            [SVProgressHUD showErrorWithStatus:@"密码不能为空"];
            return;
        }
        // 显示阴影
        [SVProgressHUD showWithStatus:@"正在登陆中" maskType:SVProgressHUDMaskTypeBlack];
        //
        NSString *format = [NSString stringWithFormat:@"http://123.123.123.123/login?username=%@&pwd=%@",userName,pwd];
        NSLog(@"%@",format);
        // 1 创建请求连接
        NSURL *url = [NSURL URLWithString:format];
        // 2 创建请求
        NSURLRequest *request = [NSURLRequest requestWithURL:url ];
        // 3 发送异步请求
        [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            // JSON:{"success":"登录成功"}
            // 4.解析服务器返回的数据(解析成字符串)
            NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            // 对字符串进行分割
            NSInteger loc = [str rangeOfString:@"\":\""].location + 3;
            NSInteger len = [str rangeOfString:@"\"}"].location - loc;
            NSString *result = [str substringWithRange:NSMakeRange(loc, len)];
            // 显示结果
            if ([result containsString:@"success"]) {
                [SVProgressHUD showSuccessWithStatus:result];
            } else{
                [SVProgressHUD showErrorWithStatus:result];
            }
        }];
    * POST请求
    NSString *format = [NSString stringWithFormat:@"http://123.123.123.123/login"];
        // 1 创建请求连接
        NSURL *url = [NSURL URLWithString:format];
        // 2 创建请求
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url ];
        // 更改请求方法
        request.HTTPMethod = @"POST";
        // 设置请求体
        request.HTTPBody = [@"username=520it&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding];
        // 设置超时
        request.timeoutInterval = 5;
        // 设置请求头
    //    [request setValue:@"ios9.0" forHTTPHeaderField:@"User-agent"];
        // 3 发送请求
        [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            if (connectionError) {
                NSLog(@"失败");
            }else{
                NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
            }
        }];
    * 路径中有汉字的话必须进行转换
    * GET:手动转换
      format = [format stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    * POST:在设置请求体时直接设置了编码格式,会自动转换
    // 设置请求体
      request.HTTPBody = [@"username=小码哥&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding];

    解析JSON

    * 服务器返回给客户端的数据一般都是JSON或者XML
    * JSON的格式很像OC中的字典和数组
         * {"name" : "jack", "age" : 10}
         * {"names" : ["jack", "rose", "jim"]}
    * 标准JSON格式的注意点:key必须用双引号
    * JSON和OC的对应关系
         JSON                    OC
         { }                    字典 NSDictionry
          []                     数组 NSArray
         “ ”                     字符串 NSString
        10,10.4             NSNumber

    IOS中JSON解决方案

    * 第三方
          *JSONKit、SBJson、TouchJSON(性能从左到右,越差)
    * 苹果原生(自带):NSJSONSerialization(性能最好)

    NSJSONSerialization

    * 解析JSON
    * data转JSON
    + (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
      // data转JSON
          NSString *str = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
    * JSON转data
    + (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
    * 关于参数
       typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
           NSJSONReadingMutableContainers = (1UL << 0), // 可变容器
           NSJSONReadingMutableLeaves = (1UL << 1), // 子节点也是可变的,也就是说转换的所有数据都是可变的
           NSJSONReadingAllowFragments = (1UL << 2) // 接收零散数据,比如说单个的‘10’,'false'
       } NS_ENUM_AVAILABLE(10_7, 5_0);
    * 参数   NSJSONReadingAllowFragments使用如下
        // 参数NSJSONReadingAllowFragments 用来读取单个元素
        NSString *str  = @"10";
        NSData *data = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
        NSLog(@"-- %@ --",data);
    * JSON转模型
    * 每次都手动去转换的话,非常费时费力。可以使用第三方框架
    * MJExtension 
    #import <MJExtension.h>
    // 获得视频的模型数组
    self.videos = [SLQVideo objectArrayWithKeyValuesArray:dict[@"videos"]];

    苹果自带的movie播放器

    * 只能播放有限的几种格式(mp4、mov等)
       // 播放视频
        NSURL *url = [NSURL URLWithString:@"http://123.123.123.123"];
        // MPMoviePlayerViewController // 视图控制器
        // MPMoviePlayerController // 内部没有view,不能直接弹出
        MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc] initWithContentURL:[url URLByAppendingPathComponent:video[@"url"]]];
        // modal 出视频并播放
        [self presentViewController:vc animated:YES completion:nil];

    字典转模型框架

    * Mantle
       * 所有模型都必须继承自MTModel
    * JSONModel
       * 所有模型都必须继承自JSONModel
    * MJExtension
       * 不需要强制继承任何其他类

    设计框架需要考虑的问题

    * 侵入性
       * 侵入性大就意味着很难离开这个框架
    * 易用性
       * 比如少量代码实现N多功能
    * 扩展性
       * 很容易给这个框架增加新框架

    解析XML

    * XML解析方式
       * SAX:逐行解释
       * DOM:一次性加载到内存
    * 苹果自带:NSXMLParser
       * SAX 方式
    * 第三方库
       * libxml2 : 纯C语言,默认包含在iOS SDK 中,,同时支持SAX、DOM
       * GDataXML : DOM方式,由google开发,基于libxml2
    * 建议
       * 大文件 : NSXMLParser、libxml2
       * 小文件 : GDataXML、XSXMLParser、libxml2

    XSXMLParser

    * 使用过程
       * 1、设置源,初始化一个XSXMLParser对象
       * 2、设置代理,实现代理方法
       * 3、启动扫描
    // 初始化方法
    - (instancetype)initWithContentsOfURL:(NSURL *)url;  // initializes the parser with the specified URL.
    - (instancetype)initWithData:(NSData *)data; // create the parser from data
    * 使用方法
    // 1 使用苹果的XML类解析xml文档
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    parser.delegate = self; // 2 设置代理
    [parser parse]; // 3 启动扫描
    * 主要是代理方法的使用
     #pragma mark -NSXMLParserDelegate代理方法
    // 读取文档开始
    - (void)parserDidStartDocument:(NSXMLParser *)parser{
    //    NSLog(@"parserDidStartDocument");
    //    self.videoArray = [NSMutableArray array];
    }
    // 读取文档结束
    -  (void)parserDidEndDocument:(NSXMLParser *)parser{
    //    NSLog(@"parserDidEndDocument--%@",self.videoArray);
    }
    // 开始读取元素,attributes 参数表示要读取的元素
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
        //    NSLog(@"didStartElement---%@",attributeDict);
        // 所有的元素都会经过这里进行读取,包括根
        // 所以要进行判断,把根给排除
        if ([elementName isEqualToString:@"videos"]) {
            return;
        }
        // 获取模型数据,放入数组
        SLQVideoItem *video = [SLQVideoItem objectWithKeyValues:attributeDict];
        [self.videoArray addObject:video];
    }
    // 读取元素结束
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    }
    格式化服务器返回的JSON数据
    * 在线格式化:http://tool.oschina.net/codeformat/json
    * 将服务器返回的字典或者数组写成plist文件

    GDataXML

    * 这个配置起来很麻烦
        * 首先不支持CocoaPods,所以只能手动拖拽进项目,而且项目比较旧。
        * 然后进入工程设置 Header Search Paths 添加/usr/include/libxml2
        * 设置工程 Other Linker Flags contain 添加 -lxml2
        * 改变文件的编译方式为非ARC - -fno -objc -arc
        * 最后编译才不会出错
    * 使用过程
        * GDataXMLDocument - 整个文档
        * GDataXMLElement - xml中某个元素        
    // 1 使用GDataXML解析xml文件
            GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
            // 2 获取所有video元素,首先要获得根节点
            NSArray *elements = [doc.rootElement elementsForName:@"video"];
            // 3 遍历所有元素
            for (GDataXMLElement *ele in elements) {
                SLQVideoItem *video  = [[SLQVideoItem alloc] init];
                // 4 获取元素属性,转换成字符串
                video.name = [[ele attributeForName:@"name"] stringValue];
                video.image  = [[ele attributeForName:@"image"] stringValue];
                video.url = [[ele attributeForName:@"url"] stringValue];
                video.length = [[[ele attributeForName:@"length"] stringValue] intValue];
                [self.videoArray addObject:video];
            }

    多值参数

    *  同一个参数传如多个数据,逗号分隔
    *  一个参数包括多个字典
    // NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/weather?place=beijing&place=shanghai"];
       NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/weather?place=beijing,shanghai"];
    解决输出到控制台显示中文乱码的问题
    * 重写descriptionWithLocale方法,这二个方法会在转换JSON时自动调用。
    @implementation NSDictionary (Log)
    - (NSString *)descriptionWithLocale:(id)locale{
        // {"weathers":[{"city":"beijing,shanghai","status":"晴转多云"}]}\
        // 将这句话格式化输出
        NSMutableString *str =[NSMutableString string];
        [str appendString:@"{\n"];
        [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            // 拼接字符串
            [str appendFormat:@"\t%@",key];
            [str appendString:@" : "];
            [str appendFormat:@"%@,\n",obj];
        }];
        [str appendString:@"}"];
        // 取出最后一个逗号
        NSRange range = [str rangeOfString:@"," options:NSBackwardsSearch];
        if (range.location != NSNotFound) {
            [str deleteCharactersInRange:range];
        }
        return str;
    }
    @end
    /*
     2015-07-15 18:43:08.137 05-掌握-多值参数[65936:116425] {
        weathers : [{
        status : 晴转多云,
        city : Beijing
     }, {
        status : 晴转多云,
        city : Shanghai}]
     }
     */
    @implementation NSArray (Log)
    - (NSString *)descriptionWithLocale:(id)locale{
        // 将这句话格式化输出
        NSMutableString *str =[NSMutableString string];
        [str appendString:@"[\n"];
        [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            [str appendFormat:@"\t%@,\n",obj];
        }];
        [str appendString:@"\t]"];
        // 取出最后一个逗号
        NSRange range = [str rangeOfString:@"," options:NSBackwardsSearch];
        if (range.location != NSNotFound) {
            [str deleteCharactersInRange:range];
        }
        return str;
    }
    @end

    文件下载

    小文件下载

     * 直接使用NSData下载
     NSData *data = [NSData dataWithContentsOfURL:url];
     * 使用NSURLConnection 异步连接
    NSURL *url  = [NSURL URLWithString:@"http://123.123.123.123/resources/images/minion_13.png"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        NSLog(@"---%zd---",data.length);
    }];
    * 使用NSURLConnection代理方式实现
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 建立连接
        NSURL *url  = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
        [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
    }
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response{
        NSLog(@"didReceiveResponse:%@",response);
        // 初始化
        self.data = [NSMutableData data];
        self.movieCount = [response.allHeaderFields[@"Content-Length"] integerValue];
    }
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
        // 缓存到内存
        [self.data appendData:data];
        CGFloat progress = 1.0 * self.data.length / self.movieCount;
        self.progressView.progress = progress;
        NSLog(@"%f",progress * 100 );
    }
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
        // 这里进行文件的保存,保存到cache里
        NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        [self.data writeToFile:[filePath stringByAppendingPathComponent:@"1.mp4"] atomically:YES];
        self.data = nil;
    }

    大文件下载

    * 使用NSURLConnection代理方式实现
    // 接收到响应的时候:创建一个空的文件
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response{
        // 获取文件长度
        self.movieCount = [response.allHeaderFields[@"Content-Length"] integerValue];
        // 创建一个空文件
        [[NSFileManager defaultManager] createFileAtPath:SLQFilePath contents:nil attributes:nil];
        // 创建文件句柄
        self.handle = [NSFileHandle fileHandleForWritingAtPath:SLQFilePath];
     }
    // 接收到具体数据:马上把数据写入一开始创建好的文件
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
        // 移动到文件末尾
        [self.handle seekToEndOfFile];
        // 写入数据
        [self.handle writeData:data];
        //
        self.currentCount += data.length;
        CGFloat progress = 1.0 * self.currentCount / self.movieCount;
        self.progressView.progress = progress;
        NSLog(@"%f",progress * 100 );
    }
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
        self.movieCount = 0;
        // 关闭文件
        [self.handle closeFile];
        self.handle = nil;
    }

    解压缩

    * 解压缩使用第三方库SSZipArchive
        // 1 使用指定文件,创建一个压缩文件
        NSArray *paths = @[
                           @"/Users/song/Desktop/test/1.png",
                           @"/Users/song/Desktop/test/2.png",
                           @"/Users/song/Desktop/test/3.png",
                           @"/Users/song/Desktop/test/4.png",
                           @"/Users/song/Desktop/test/5.png"
                           ];
        [Main createZipFileAtPath:@"/Users/song/Desktop/test.zip" withFilesAtPaths:paths];
        // 2 使用指定目录创建一个压缩文件
        [Main createZipFileAtPath:@"/Users/song/Desktop/test121212.zip" withContentsOfDirectory:@"/Users/song/Desktop/test"];
        // 3 解压缩一个文件到指定目录
        [Main unzipFileAtPath:@"/Users/song/Desktop/test.zip" toDestination:@"/Users/song/Desktop"];

    文件上传

        // 一定要注意这个格式是固定的
        /* 文件参数格式
         --分割线\r\n
         Content-Disposition: form-data; name="参数名"; filename="文件名"\r\n
         Content-Type: 文件的MIMEType\r\n
         \r\n
         文件数据
         \r\n
         */
        // 文件上传
        // 1、创建请求
        NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/upload"];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        // 2、设置协议
        request.HTTPMethod = @"POST";
        // 3、设置请求头
        [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",SLQBoundary] forHTTPHeaderField:@"Content-Type"];
        // 4、设置请求体
        NSMutableData *body = [NSMutableData data];
        // 设置文件参数
        // 设置边界
        [body appendData:SLQUTF(@"--")];
        [body appendData:SLQUTF(SLQBoundary)];
        [body appendData:SLQEnter];
        // 文件参数名
        [body appendData:SLQUTF([NSString[] stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"1.png\""])];
        [body appendData:SLQEnter];
        // 文件类型
        [body appendData:SLQUTF([NSString stringWithFormat:@"Content-Type: image/png"])];
        [body appendData:SLQEnter];
        // 文件内容
        [body appendData:SLQEnter];
        UIImage *image = [UIImage imageNamed:@"1"];
        [body appendData:UIImagePNGRepresentation(image)];
        [body appendData:SLQEnter];
    
        /* 非文件参数格式
         --分割线\r\n
         Content-Disposition: form-data; name="参数名"\r\n
         \r\n
         参数值
         \r\n
         */
        // 设置非文件参数
        [body appendData:SLQUTF(@"--")];
        [body appendData:SLQUTF(SLQBoundary)];
        [body appendData:SLQEnter];
    
    
        [body appendData:SLQUTF([NSString stringWithFormat:@"Content-Disposition: form-data; name=\"username\""])];
        [body appendData:SLQEnter];
    
    
        [body appendData:SLQEnter];
        [body appendData:SLQUTF(@"bulabulabula")];
        [body appendData:SLQEnter];
    
    
        /* 结束标记
         --分割--线\r\n
         \r\n
         */
        // 结束标记
        [body appendData:SLQUTF(@"--")];
        [body appendData:SLQUTF(SLQBoundary)];
        [body appendData:SLQUTF(@"--")];
        [body appendData:SLQEnter];
        request.HTTPBody = body;
    
        [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            //  这个方法会调用descriptionWithLocale方法,可以在这里解决输出到控制台显示中文乱码的问题
            NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
        }];

    获取MIMEType

    * OC 方法
    - (NSString *)getMIMEType:(NSString *)path{
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]];
        NSURLResponse *response = nil;
        [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
            return response.MIMEType;
    }
    * c语言
    // 要包含头文件MobileCoreServices.h
    + (NSString *)mimeTypeForFileAtPath:(NSString *)path{
        if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
            return nil;
        }
        CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[path pathExtension], NULL);
        CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
        CFRelease(UTI);
        if (!MIMEType) {
            return @"application/octet-stream";
        }
        return (__bridge NSString *)(MIMEType);
    }

    NSOutputStream

    * 文件流,文件输出流,可以输出到内存、硬盘、NSData
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 建立连接
        NSURL *url  = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
        [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
    }
    /**
     * 接收到响应的时候:创建一个空的文件
     */
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response{
        // 获取服务器那里给出的建议名字   response.suggestedFilename);
        NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
        // 创建文件流
        self.stream = [[NSOutputStream alloc] initToFileAtPath:path append:YES];
        // 打开文件流
        [self.stream open];
    }
    /**
     * 接收到具体数据:马上把数据写入一开始创建好的文件
     */
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
        // 参数1要求是bytes
        [self.stream write:[data bytes]  maxLength:data.length];
        NSLog(@"---");
    }
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
        // 关闭文件流
        [self.stream close];
    }

    NSURLConnection和NSRunLoop

    * 使用NSURLConnection创建的请求,其内部和NSRunLoop有关联,必须保证NSRunLoop处于运行状态,否则代理方法运行起来就会出问题。
    * 如果要在子线程里创建请求,必须要手动启动NSRunLoop,并且要在方法使用结束手动关闭NSRunLoop。
    // 建立连接
    NSURL *url  = [NSURL URLWithString:@"http://123.123.123.123/resources/images/minion_05.png"];
    NSURLConnection *con = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
    // 决定代理方法在哪个队列中执行
    [con setDelegateQueue:[[NSOperationQueue alloc] init]];
    // 开启子线程runloop
    self.runloop =  CFRunLoopGetCurrent();
    CFRunLoopRun();
    在代理方法中使用完毕,停止runloop
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
        NSLog(@"--connectionDidFinishLoading--%@",[NSThread currentThread]);
        CFRunLoopStop(self.runloop);
    }

    NSURLSession

    * 这个是在iOS7之后推出的用于替代NSURLConnection的新类,推荐掌握这个。
    * NSURLSession 主要由两部分组成,一个是Session实例对象,一个是任务。
    * 使用步骤
       * 创建task(dataTaskWithRequest),启动task(resume
       * 抽象类,使用其子类(NSURLSessionDataTaskNSURLSessionDownloadTaskNSURLSessionUploadTask
       * 大小文件都一样,默认写入到tmp目录下面,下载完毕后要自己移动文件
    * NSURLSession 代理
       * 初始化时设置代理<NSURLSessionDataDelegate>
       * 实现过程
            * 接收响应,指定响应方式:取消、下载、变为下载 didReceivedResponse
            * 接收数据didReceivedData
            * 接收完毕(成功和失败都会进入这个方法)didComplete
       * 这个可以实现大文件下载
    * 大文件断点下载
       * NSURLSession 的方法:suspend、resume、cancel
       * resumeData 保存暂停时程序数据状态,取消任务后要根据状态恢复下载
       *(不好 ,实现复杂)将下载的tmp文件保存到cachae,然后恢复现在时再从cache移动到临时文件
       * 下载失败后要从NSError中获取失败时的恢复数据
    * 何为断点下载
       * 程序因意外事件终止,导致下载被停止,主要考虑用户突然关闭程序。
       * 可以将下载的数据同步到沙盒中,并且记录下载大小,以及记录已下载的文件,每次下载之前都进行扫描一番。
       * 如果下载一半就在请求头里指定要下载的范围
    * 上传
       * NSURLSessionUploadTast
       * POST 请求设置注意methodBody为上传的参数fromData
       * NSURLSessionConfiguration 统一配置(比如可以在这里设置是否允许设置程序使用蜂窝移动网络)

    GET

    NSURL *url  = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=4324"];
    // 1 获得NSURLSession单例对象
    NSURLSession *session = [NSURLSession sharedSession];
    // 2 创建任务
    NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    // 4 处理数据
    NSLog(@"----%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
    }];
    // 3 启动任务
    [task resume];

    POST

     // post请求
        NSURL *url  = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=4324"];
        // 获得NSURLSession单例对象
        NSURLSession *session = [NSURLSession sharedSession];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        // 设置请求头
        request.HTTPMethod = @"POST";
        // 设置请求体
        NSMutableData *body  = [NSMutableData data];
        [body appendData:[@"username=123&pwd=234" dataUsingEncoding:NSUTF8StringEncoding]];
        request.HTTPBody = body;
        // 创建任务
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            NSLog(@"----%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
        }];
        // 启动任务
        [task resume];

    下载

    * 直接使用downloadTaskWithURL:url进行下载,不过下载成功的文件是放在tmp临时目录里面的,一定要及时把文件给移出来。
    NSURL *url  = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
    // 获得NSURLSession单例对象
    NSURLSession *session = [NSURLSession sharedSession];
    // 创建任务
    NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
        NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
        // 这个方式下载的文件在tmp文件夹下,要把下载的文件移动到cache中永久保存,参数是 fileURLWithPath,看清了
        // loaction 表示在本地临时存储区的路径
        [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
    }];
    // 启动任务
    [task resume];

    代理方式

    - (void)viewDidLoad {
        [super viewDidLoad];
        NSURL *url  = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
        // 创建
        NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
        // 创建任务
        NSURLSessionDataTask *task = [session dataTaskWithURL:url];
        // 启动任务
        [task resume];
    }
    // 接收服务器响应,必须手动执行后续的执行方式(允许接收数据还是不允许接收)
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
        NSLog(@"%s",__func__);
        // 必须手动指定接下来的数据要不要接收
        completionHandler(NSURLSessionResponseAllow);
    }
    // 接收数据,多次调用
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
        NSLog(@"%s",__func__);
    }
    // 下载完毕后调用,如果失败,看参数error的值
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
        NSLog(@"%s",__func__);
    }
    typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {
        NSURLSessionResponseCancel = 0,/* Cancel the load, this is the same as -[task cancel] */
        NSURLSessionResponseAllow = 1,/* Allow the load to continue */
        NSURLSessionResponseBecomeDownload = 2,/* Turn this request into a download */
    } NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);

    断点下载

    * 通过自定义NSURLSession ,使用dataWithTask来进行下载,并且手动控制器下载文件的去向。
    * 每次下载之前都要去沙盒读取已下载的文件,用于判断从哪里进行下载
    * 主要方法如下:
    - (NSURLSessionDataTask *)dataTask{
        if (!_dataTask) {
            // 获取下载进度,直接从沙盒中读取文件长度
            NSInteger total = [[NSMutableDictionary dictionaryWithContentsOfFile:SLQDownloadFilePath][SLQFileName] integerValue];
            NSInteger current = [[[NSFileManager defaultManager] attributesOfItemAtPath:SLQFilePath error:nil][NSFileSize] integerValue];
            if (total && total == current ) {
                NSLog(@"已经下载完毕");
                return nil;
            }
            // 如果长度和
            NSURL *url  = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
            // 指定要从服务器获取的数据的范围
            NSString *range = [NSString stringWithFormat:@"bytes=%zd-",current];
            [request setValue:range forHTTPHeaderField:@"Range"];
            // 创建任务
            _dataTask = [self.session dataTaskWithRequest:request];
        }
        return  _dataTask;
    }
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
    //    NSLog(@"----%@",[response class]);
        // 开启输出流
        [self.stream open];
        // 计算总得数据长度,response会返回请求的数据长度,不包括已经下载的数据长度,所以要累加起来
        self.totalCount = [response.allHeaderFields[@"Content-Length"] integerValue] + SLQFileLength;
        NSString *name = response.suggestedFilename;
        // 存储总长度,将所要下载的文件长度保存起来
        NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:SLQDownloadFilePath];
        if (dict == nil) {
            dict = [NSMutableDictionary dictionary];
        }
        dict[SLQFileName] = @(self.totalCount);
        [dict writeToFile:SLQDownloadFilePath atomically:YES];
        // 继续下载
        completionHandler(NSURLSessionResponseAllow);
    }
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
        // 写入数据到沙盒
        [self.stream write:[data bytes]maxLength:data.length];
        // 获取下载进度,直接从沙盒中读取文件长度
        NSLog(@"---%f",1.0 * SLQFileLength / self.totalCount);
    }
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
        // 清空
        self.dataTask = nil;
        [self.stream close];
        self.stream = nil;
    }

    NSURLSession 上传文件

      * 必须按照格式写,一个空格或者回车都不能多。   
     // 一定要注意这个格式是固定的
        /* 文件参数格式
         --分割线\r\n
         Content-Disposition: form-data; name="file"; filename="文件名"\r\n
         Content-Type: 文件的MIMEType\r\n
         \r\n
         文件数据
         \r\n
         // 结束标记
         \r\n
         --分割线--\r\n
         \r\n
         */
         // 主要是参数第二个参数要传入 **`请求体`**
           [[self.session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            NSLog(@"---%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
        }] resume];

    AFNetworking

    * GET\POST
       * AFHTTPRequestManager

       * AFHTTPSessionManager

    - (void)GET{
        // GET
        AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
        // 将数据作为参数传入
        NSDictionary *dict = @{
                               @"username":@"12",
                               @"pwd":@"13"
                               };
        [mgr GET:[NSString stringWithFormat:@"http://123.123.123.123/login"] parameters:dict success:^(NSURLSessionDataTask *task, id responseObject) {
            NSLog(@"success:%@",responseObject);
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            NSLog(@"failure:%@",error);
        }];
    }
    - (void)POST{
        // POST
        AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
        // 将数据作为参数传入
        NSDictionary *dict = @{
                               @"username":@"12",
                               @"pwd":@"13"
                               };
        [mgr POST:[NSString stringWithFormat:@"http://123.123.123.123/login"] parameters:dict success:^(NSURLSessionDataTask *task, id responseObject) {
            NSLog(@"success:%@",responseObject);
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            NSLog(@"failure:%@",error);
        }];
    }
    * 文件上传:appendPartWithFileData:
    - (void)upload{
        // 文件上传
        AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
        // 将数据作为参数传入
        [mgr POST:@"http://123.123.123.123/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
            // formdata 为要上传的数据
    //        [formData appendPartWithFileURL:[NSURL fileURLWithPath:@"/Users/song/Desktop/test.png"] name:@"file" error:nil];
            [formData appendPartWithFileData:[NSData dataWithContentsOfFile:@"/Users/song/Desktop/test.png"] name:@"file" fileName:@"wer.png" mimeType:@"image/png"];
        } success:^(NSURLSessionDataTask *task, id responseObject) {
            NSLog(@"success:%@",responseObject);
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            NSLog(@"failure:%@",error);
        }];
    }
    * 文件下载
        * 下载文件需要返回一个保存路径,还需要手动启动resume
    - (void)download{
        // 下载
        AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
        [[mgr downloadTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://123.123.123.123/resources/images/minion_02.png"]] progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
            // 下载文件需要返回一个保存路径,还需要手动启动resume
            NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
            return [NSURL fileURLWithPath:[path stringByAppendingPathComponent:response.suggestedFilename]];
        } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
            NSLog(@"%@",filePath.path);
        }] resume];
    }
    * 默认是解析json,如果想解析xml,需要指定管理器的解析器为xml
       * 如果解析其他类型的文件,就将responseSerializer属性设置为ADHTTPResonseSericlizer,服务器返回什么就接受什么类型的数据。
    -(void)returnType{
        // 默认返回的数据时JSON,如果想返回XML,设置属性responseSerializer
        // 如果想返回服务器上文件本来的类型,设置AFHTTPResponseSerializer
        AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
        // responseSerializer 用来解析服务器返回的数据
        mgr.responseSerializer = [AFHTTPResponseSerializer serializer]; // 直接使用“服务器本来返回的数据”,不做任何解析
        // 告诉AFN,以XML形式解析服务器返回的数据
        //    mgr.responseSerializer = [AFXMLParserResponseSerializer serializer];
        // 将数据作为参数传入
        [mgr GET:[NSString stringWithFormat:@"http://123.123.123.123/resources/images/minion_02.png"] parameters:nil success:^(NSURLSessionDataTask *task,id response) {
            NSLog(@"success:%zd",[response length]);
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            NSLog(@"failure:%@",error);
        }];
    }

    手机联网状态

    - 手机联网状态:`AFNetWorkReachabityManager`
    - 苹果自带:`Reachability` ,通过通知监听系统状态

    * 手机联网状态:AFNetWorkReachabityManager
    - (void)monitor{
        // 监控网络状态
        AFNetworkReachabilityManager *mgr  = [AFNetworkReachabilityManager sharedManager];
        // 网络状态改变就会调用这个block
        [mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
            NSLog(@"网络状态改变:%zd",status);
        }];
        // 打开监听器
        [mgr startMonitoring];
    
        /*
        typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
         AFNetworkReachabilityStatusUnknown          = -1, // 未知
         AFNetworkReachabilityStatusNotReachable     = 0, // 未联网
         AFNetworkReachabilityStatusReachableViaWWAN = 1, // 蜂窝网络
         AFNetworkReachabilityStatusReachableViaWiFi = 2, // wifi
         };
         */
    }
    * 手机联网状态:Reachability
        * 手机的状态改变,会给系统发送通知,所以可以添加监听器,接收这个通知。
    /**通知*/
    @property (nonatomic, strong) Reachability *reach;
    - (void)viewDidLoad{
        [super viewDidLoad];
        // 添加通知
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getNetworkStatus) name:kReachabilityChangedNotification object:nil];
        // 接收通知
        self.reach = [Reachability reachabilityForInternetConnection];
        [self.reach startNotifier];
    }
    - (void)getNetworkStatus{
        /*
         typedef enum : NSInteger {
         NotReachable = 0, // 网络不可知
         ReachableViaWiFi, // WIFI
         ReachableViaWWAN  // 移动网络
         } NetworkStatus;
         */
        // 获取手机网络状态
        if([Reachability reachabilityForLocalWiFi].currentReachabilityStatus != NotReachable)
        {
            NSLog(@"wifi");
        }
        else if([Reachability reachabilityForInternetConnection].currentReachabilityStatus != NotReachable)
        {
            NSLog(@"3G?4G");
        }
        else
        {
            NSLog(@"Nothing at all!");
        }
    }
    - (void)dealloc
    {
        // 停止监听器
        [self.reach startNotifier];
        // 移除通知
          [[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil];
    }

    MD5加密

    * 使用:主要是对用户的敏感信息进行加密
        * 对输入信息生成唯一的128位散列值(32个字符)
        * 根据输出值,不能得到原始的明文,即其过程不可逆
    * MD5改进
        * 加盐(Salt):在明文的固定位置插入随机串,然后再进行MD5
        * 先加密,后乱序:先对明文进行MD5,然后对加密得到的MD5串的字符进行乱序
        * 等等,就是让信息更加复杂

    HTTPS

    * 使用https要实现代理方法 didReceiveChallenge
    * 1 创建HTTPS链接
       _dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        }];
    * 2 实现代理方法 didReceiveChallenge
    /** 代理方法
     * challenge : 挑战、质询
     * completionHandler : 通过调用这个block,来告诉URLSession要不要接收这个证书
     */
    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
    {
        // NSURLSessionAuthChallengeDisposition : 如何处理这个安全证书
        // NSURLCredential :安全证书
    //    NSLog(@"%@",challenge);
        if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            return;
        }
        if(completionHandler)
        {
            // 利用这个block说明使用这个证书
            completionHandler(NSURLSessionAuthChallengeUseCredential,challenge.proposedCredential);
        }
    }

    UIWebView

    * 显示网页数据
    * 代理方法<UIWebViewDelegate>
        * shouldStartLoadWithRequest: 请求之前判断是否允许访问(过滤某些网址)
        * 属性UIScrollView可以控制滚动范围
        * loadHTMLString
        * loadData
        * 可以加载网络资源和本地资源
        * scalesPageToFit 屏幕自适应
        * dataDetectorTypes 自动检测网页中出现的电话号码,网址等,添加下划线和链接。
    // 始发送请求(加载数据)时调用这个方法
    - (void)webViewDidStartLoad:(UIWebView *)webView;
    // 请求完毕(加载数据完毕)时调用这个方法
    - (void)webViewDidFinishLoad:(UIWebView *)webView;
    // 请求错误时调用这个方法
    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
    // UIWebView在发送请求之前,都会调用这个方法,如果返回NO,代表停止加载请求,返回YES,代表允许加载请求
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
    <span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">/*</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">* 每当webView即将发送一个请求之前,都会调用这个方法</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">* 返回YES:允许加载这个请求</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">* 返回NO:禁止加载这个请求</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">*/</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">     NSLog(@"%s",__func__);</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">    if ([request.URL.absoluteString containsString:@"life"]) {</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">        return NO;</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">    }</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">    return YES;</span><br style="font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif;" /><span style="font-size:12px;font-family: 'Helvetica Neue', Helvetica, Arial, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Microsoft Yahei', sans-serif; color: rgb(51, 51, 51);">}</span>

    JS介绍

    HTML5
       * html(内容) + CSS(样式) + JS(动态效果、事件交互)
       * 常用JS函数
            * -alert(10); // 弹框
            * document.getElementById(‘test’); // 根据ID获得某个DOM元素
       * JS和OC通信
       * oc执行js
            * stringByEvaluatingJavaScriptFromString
            * JS 函数
            * function
      * JS执行OC
            * 通过代理法方法 shouldStartLoadWithRequest
            * 在js函数中调用 loaction.href = 'slq://sendMessage_?参数1&参数2';
            * 传递参数的话,在方法后边写入一符号(_、@等)标识要传递参数,然后参数之间也要加入符号分割

    OC执行JS

      * 是用OC执行那个JS脚本
      * stringByEvaluatingJavaScriptFromString
       [webView stringByEvaluatingJavaScriptFromString:@"alert(100)"];
       // 调用JS中的函数,
        NSLog(@"%@",[webView stringByEvaluatingJavaScriptFromString:@"login();"]);
        self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title;"];

    JS执行OC

    * 通过代理法方法 shouldStartLoadWithRequest
    * 无参数传递
    /**
     * 通过这个方法完成JS调用OC
     * JS和OC交互的第三方框架:WebViewJavaScriptBridge
     */
     // location.href = 'slq://call';
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
        //
        NSLog(@"%@",request.URL);
        NSString *url = request.URL.absoluteString;
        NSString *pre = @"slq://";
        if([url hasPrefix:pre]){
            // 调用OC方法
    //        NSLog(@"调用OC方法");
            NSString *method = [url substringFromIndex:pre.length];
            // NSSelectorFromString 将字符串转换成方法名
            [self performSelector:NSSelectorFromString(method) withObject:nil];
            return NO;
        }
    //    NSLog(@"发送请求");
        return YES;
    }
    * 2个参数
       * 使用'_'代替':','?'区分参数和函数名,'&'区分参数
    // location.href = 'slq://call2_number2_?&100';
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
        NSString *url = request.URL.absoluteString;
        NSString *pre = @"slq://";
        if([url hasPrefix:pre])
        {
            // 调用OC方法
            NSString *method = [url substringFromIndex:pre.length];
            // method = call2_number2_?200&300
            // 分割字符串
            NSArray *arr = [method componentsSeparatedByString:@"?"];
            // call2:number2:
            NSString *methodName = [[arr firstObject] stringByReplacingOccurrencesOfString:@"_" withString:@":"];
            // 200&300
            NSString *paramStr = [arr lastObject];
            NSArray *params = nil;
            if (arr.count == 2 && [paramStr containsString:@"&"]) {
                params = [paramStr componentsSeparatedByString:@"&"];
            }
            NSString *param1 = [params firstObject];
            NSString *param2 = params.count <= 1 ? nil : [params lastObject];
            NSLog(@"%@",methodName);
            [self performSelector:NSSelectorFromString(methodName) withObject:param1 withObject:param2]; // 两个参数
    //        [self performSelector:NSSelectorFromString(methodName) withObject:para];// 一个参数
            return NO;
        }
        return YES;
    }
    * 3个参数
      * 如果有3个以上参数,只能使用方法签名的方式来确定传递参数
    - (id)performSelector:(SEL)selector withObjects:(NSArray *)params{
        // 设置方法签名
        NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:selector];
        //
        if (sig == nil) {
            NSLog(@"方法没找到");
        }
        // NSInvocation 包装对象利用一个NSInvocation对象包装一次方法调用(方法调用者、方法名、方法参数、方法返回值)
        NSInvocation *invo = [NSInvocation invocationWithMethodSignature:sig];
        invo.target = self;
        invo.selector = selector;
        // 设置参数
        NSInteger paramNum = sig.numberOfArguments - 2; // 包含两个隐含参数:self and _cmd
        // 取最小值作为参数,
        paramNum = MIN(paramNum, params.count);
        for (int i = 0 ; i < paramNum; i ++) {
            id obj = params[i];
            if ([obj isKindOfClass:[NSNull class]]) {
                continue;
            }
            [invo setArgument:&obj atIndex:i + 2]; // 从第三个参数开始
        }
        // 设置回调
        [invo invoke];
        // 返回值
        id returnVal = 0;
        if (sig.methodReturnLength) {
            [invo getReturnValue:&returnVal];
        }
        return returnVal;
    }

    程序崩溃处理

      * 在appdelegate中判断
    void handleException(NSException *exception){
        [[UIApplication sharedApplication].delegate performSelector:@selector(handle)];
    }
    - (void)handle{
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"哈哈" message:@"崩溃了把" delegate:self cancelButtonTitle:@"好的" otherButtonTitles:nil, nil];
        [alertView show];
        // 重新启动RunLoop
        [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
    }
    
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
        NSLog(@"-------点击了好的");
        exit(0);
    }
    
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // 设置捕捉异常的回调
        NSSetUncaughtExceptionHandler(handleException);
        return YES;
    }

    去除Xcode编译警告

       * 如果对于某些警告需要屏蔽,需要找到这个警告 的代号
     // 去除Xcode编译警告
    //#pragma clang diagnostic push // 开始
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    //#pragma clang diagnostic pop // 结束

    异常处理

       * 如果方法名错误,抛出异常 @throw
       * 捕获异常 @try @catch @finally

    展开全文
  • 在我们进行的网络请求中,服务器得到的数据是乱的,具体混乱格式及情况如下: 1.api接口如下: 2.创建retrofit实例: 3.网络工具类的单例化 4.提供一个对外的方法 5.在activity里面调用api及...

    在我们进行的网络请求中,服务器得到的数据是乱的,具体混乱格式及情况如下:

    1.api接口如下:


    2.创建retrofit实例:


    3.网络工具类的单例化


    4.提供一个对外的方法


    5.在activity里面调用api及网络工具类


    然后我们传入一个map集合到getallcar方法里面,然后服务器收到了一串乱码,然后我和后台对接了半天,发现原因如下:

    1.后台接口有问题

    2.后台收到数据没转码

    3.网络框架有漏洞

    4.我这边没转码

    最后我们一一排查,发现

    1是没有问题的,因为ios那边上传同样接口,并没有出现乱码的问题。排除这个问题

    2这个方案的话,和后台交流之后,他同意转码,并且成功返回接口数据,但是如此将会导致其他前端访问数据出现问题,比如这一次它后台转码之后,web端访问数据时就出现了乱码。所以此方案不可行。

    3.当排除前面这两种情况之后,到第三种时候,突然发现好傻,square公司不可能出现这种低级错误。所以,排除这个问题

    4.最后一个解决方案,当然,到了这步确实解决了,不过试了很久才发现问题解决了。首先是我这边明文将map里面的元素转码,实验之后不可行。然后我开始用

    @FormUrlEncoded + 请求参数为
    @FieldMap Map<String,Object> map 来解决
    这方案接近正确,但是还是缺少最重要的一步,那就是添加请求头用来转码了,也就是:

    @Headers("Content-Type: application/json; charset=utf-8")
    最后,问题解决。

    将api格式请求从:

    @POST("traceList")
    Call<CarTraceListEntity> getCarTraceList(@QueryMap Map<String,Object> map);
    改为:

    @FormUrlEncoded
    @Headers("Content-Type: application/json; charset=utf-8")
    @POST("traceList")
    Call<CarTraceListEntity> getCarTraceList(@FieldMap Map<String,Object> map);
    问题解决。

    展开全文
  • IOS开发笔记:IOS的零零散散记录

    千次阅读 2013-10-12 14:07:42
    IOS armv Armv6:iPhone 2G/3G、ipod1G/2G Armv7:iPhone3GS/4/4s、ipod3G/4G、ipad1G/2G/3G Armv7s:iPhone5 URL中含有% 当你的接口中含有%22时你要将其替换为\",否则客户端是无妨访问。你将含有%22的接口复制到...

    IOS armv

    Armv6:iPhone 2G/3G、ipod1G/2G

    Armv7:iPhone3GS/4/4s、ipod3G/4G、ipad1G/2G/3G

    Armv7s:iPhone5


    URL中含有%

    当你的接口中含有%22时你要将其替换为\",否则客户端是无妨访问。你将含有%22的接口复制到浏览器中进行打开,观察URL的变化,你会发现,原来有%22的地方都被编码成\",当你再次从浏览器复制出来时,URL有还原成原来含有%22的URL,所以客户端在使用时要将其手动替换。


    NSUserDefault存储NSMutableDictionary

    在用NSUserDefaulsts存储值的时候,如果有很多值并且有一定相关性,则可以用 NSDictionary存储,如:

    NSDictionary*authData = [NSDictionarydictionaryWithObjectsAndKeys:

                                 sinaweibo.accessToken, @"AccessTokenKey",

    sinaweibo.expirationDate, @"ExpirationDateKey",

                                 sinaweibo.userID, @"UserIDKey",

                                 sinaweibo.refreshToken, @"refresh_token", nil];

    但有一点需要注意!NSUserDefaults不管你存进去的是可变字典还是不可变字典,它一律给你当成不可变字典,所以如果要取出来当可变字典用,可以如下:

    NSMutableDictionary *shareTime = [[defaultsobjectForKey:@"shareTime"] mutableCopy];


    KVO实现时要注意的

    在实现KVO时,如果几个controller中展示的是一样的数据,变化是一起的,要将此数据封装成一个类,并使用单例,然后多个controller对它进行观察。


    IOS 图像

    1、CGImageRef pickImage =(CGImageCreateWithImageInRect([image CGImage], rect));

    使用这个则必须调用相应的释放方法,即使已经使用了arc

    CGImageRelease(pickImage);      

    2、uiedgeinsetsmake(image.size.heigh/2,image.size.width/2,image.size.hegit/2,image.size.width/2)

    让Image当背景,会被拉伸。为什么这样呢?

    正常拉伸图片只允许在top—bottom之间留1px被拉伸,即first and third参数,left—right之间留1px被拉伸,即second and fourth 参数。


    界面消失与出现 delegate

    [self dismissViewControllerAnimated:YEScompletion:^{

                   [self.delegate numberOfRowsSelected:[objects count] withData:objects];   }];

    如果放出去让delegate执行的方法,要这样,以保证delegate里有pressentViewController时,当前界面正常消失,后面的界面正常出现


    可以通用的类的设计技巧

    如果一个界面可以用来共用,比如table用来选择,则可以在点击确定按钮的执行方法中或点击每一个行时,用代理方法,将由此类获得的数据传递出去,具体要怎么处理则由实现这个代理的类去做。


    关于JSON

    1、Json格式如果数据是很长的文字,那么文字中不能有空白、换行等,否则getJson和ajax都不会执行。

    2、以后用CJSONDeserializer.hCJSONDeserializer.h解析Json数据时,如果出现Failed to scan a value,一定是json字符串的格式有问题,一定仔细检查。


    时间戳

    时间戳,即距离1970年1月1日的秒数,到目前为止是一个10位的整数,用NSUInteger转换就行了。


    UIWebView与JS交互

    1、如果想要在html已加载的时候就给某个变量赋值,可以在(void)webViewDidFinishLoad:(UIWebView*)webView1//加载完成 中进行处理。

    2、如果加载本地的html,里面的js突然不执行了,很大可能就是js代码由于之前的改动,出现了错误。


    IOS 数组

    1、如果输出结果为这样的(

       imglist

    )说明这个一个二维数组。


    关于Itunes Connect上传

    1、itunes connect不能轻易删除已经创建的APP,否则这个APP的已填信息都不能在使用了,以后要记住在删除东西之前要确保没有问题,不能轻易执行删除操作!!!!


    HTTP请求

    1、Content-type

    Content-Type指定要求的那个文件的类型是什么,对于正常的HTTP Post请求,需指定[request setValue:@"application/x-www-form-urlencoded"forHTTPHeaderField:@"Content-Type"];

    3、在HTTP POST中传递参数时,如果是中文要转成unicode。

    4、ASIHTTPRequest中,[request setResponseEncoding:NSUTF8StringEncoding];如果接收到的是乱码则这样设置不管用,直接改它里面的返回数据的编码。


    IOS 字符串

    1、NSString的stringByAppendingString方法是将拼接后的字符串返回,所以一定要让原来的等于才行,如 NSString *str = @””;

    str =[str stringByAppendingString];


    关于XCode设置

    1、开启调试exc_bad_access

    在xcode中设置的步骤:

    product->Scheme->Editor Scheme。

    展开全文
  • iOS Charles抓包

    2019-02-27 16:38:16
    前言:在iOS应用开发过程中,通过抓包调试服务接口的场景时常出现。Charles和Wireshark是我在iOS开发过程中最常用的两款软件。 在日常开发中,我们无法看到应用程序与服务器之间发送和接收的内容,没有这种可见性,...

    级别:★★☆☆☆
    标签:「iOS手机抓包」「iOS HTTPS抓包」「Charles证书」
    作者: Xs·H
    审校: QiShare团队


    前言:在iOS应用开发过程中,通过抓包调试服务接口的场景时常出现。Charles和Wireshark是我在iOS开发过程中最常用的两款软件。

    在日常开发中,我们无法看到应用程序与服务器之间发送和接收的内容,没有这种可见性,我们在确定故障的确切位置时会非常困难且耗时。而Charles是一个运行在PC上的Web代理,我们将应用程序配置为通过Charles访问网络,便可以在Charles上记录并显示发送和接收的所有数据,进而可以大大提高调试程序的效率。Charles官网

    从下图可以看出Charles的角色:

    Charles有以下几个常用功能:

    • 请求预览:通过分组或序列视图预览和过滤请求数据;
    • 请求抓包:抓取HTTP和HTTPS的请求数据和响应数据;
    • 请求断点:拦截指定的请求或响应,预览中间的数据;
    • 数据修改:修改请求数据和响应数据以配合数据测试;
    • 请求重发:指定请求重复发送,以测试后端功能和性能;
    • 网速模拟:设置网速延迟,模拟手机上2G/3G/4G网络;

    由于Charles的功能很多,很难在文章中详尽介绍,所以作者以在项目中对Charles的使用为切入点,对最常用、最有用的几个功能进行介绍。

    一、安装

    Charles是收费软件,有30天的免费试用期限,之后每使用30分钟会被强退一次,重启后可继续使用。从Charles官网可以获取Charles安装包,也可以从互联网中查找破解版。

    下载破解版时要注意甄别安装包来源,谨防木马和病毒。

    二、请求预览

    Charles启动后,就运行在抓包模式。由于Charles会自动配置PC浏览器的代理,所以,随意打开一个网页(只要有网络请求即可)即可预览到请求信息。

    如果使用插件为浏览器设置了独立代理,请关闭插件或者设置成系统代理。

    Charles提供了Structure和Sequence两种预览模式。 Structure以域名对请求进行分组,可以很方便地预览同一域名下的请求数据,也方便于日常开发中对某一服务接口的分析和处理。图示如下:

    Sequence以时间顺序显示请求信息,可以最直接的预览请求信息。在此模式下,可以使用Filter过滤请求,针对性分析。图示如下:

    在两种模式下,都可以通过切换标签(Overview、Request、Response等)预览不同类型的请求信息。在最常用的Request和Response标签下,还可以通过切换子标签(Headers、Cookies、Text等)预览对应标签详细内容。图示如下:

    三、请求抓包

    使用工具栏的白圆红点按钮(快捷键是“Command+R”)可以使Charles在抓包(Start Recording)和不抓包(Stop Recording)之间切换。使用此按钮,在需要调试时再打开抓包功能可以有效减少干扰信息,而快速抓取到需要调试的请求。

    对从手机(以iPhone示例)发出的请求进行抓包,需要保证iPhone和PC工作在同一局域网内。

    1. 获取PC的IP地址

    在Charles菜单栏 -> Help -> Local IP Address中可以查看PC的IP地址。图示如下:

    也可以在Mac终端使用命令ifconfig en1查看PC的IP地址。图示如下:

    2. 配置iPhone代理

    在iPhone的设置 -> 无线局域网 -> 局域网信息(i) -> 配置代理 -> 手动中配置代理,服务器输入框中填写PC的IP地址,端口输入框中填写Charles的代理端口(一般是8888)。图示如下:

    具体的端口可以从Charles菜单栏 -> Proxy -> Proxy Settings中查看。图示如下:

    iPhone代理配置完成后,Charles会弹出连接提示框,点击Allow之后即可使用Charles对从该iPhone发出的请求进行抓包了。图示如下:

    3. 抓包HTTPS请求

    在配置iPhone代理完毕后,就可以通过Structure或者Sequence窗口预览HTTP请求的数据了。但由于HTTPS请求被加密过,预览请求时只能预览到乱码数据。要预览到HTTPS请求的数据明文,需要PC和iPhone安装证书授权。

    1) PC安装证书

    在Charles菜单栏 -> Help -> SSL Proxying -> Install Charles Root Certificate中可以为PC安装证书,证书可以在Mac的钥匙串中查看。图示如下:

    证书可以在Mac的钥匙串中查看,双击证书,将信任权限设定为始终信任。图示如下:

    2) iPhone安装证书

    在iPhone浏览器中访问http://charlesproxy.com/getssl可以下载证书并安装。此地址一般不会变化,可以在Charles菜单栏 -> Help -> SSL Proxying -> Install Charles Root Certificate on a Mobile Device or Remote Browser中查看最新的官方证书下载地址。图示如下:

    基于iOS的证书信任机制,在安装完成并信任证书后,需要到iPhone设置 -> 关于本机 -> 证书信任设置中启用根证书。图示如下:

    这样,就可以使用Charles中抓包iPhone发出的HTTPS请求并预览明文数据了。

    抓包模拟器上的HTTPS请求需要点击Install Charles Root Certificate in iOS Simulators安装证书。

    3) 启动抓包SSL权限

    在Charles菜单栏 -> Proxy -> SSL Proxying Settings中勾选Enable SSL Proxying,然后在Locations中添加需要抓包的Host和Port即可。图示如下:

    也可以在抓包界面,右键点击某条/组请求,在弹出的选项列表中点击Enable SSL Proxying启用权限。图示如下:

    四、请求断点

    在Charles的请求预览界面中,右键点击某条/组请求,在弹出的选项列表中有Breakpoints选项。图示如下:

    点击Breakpoints后即为该请求设定了断点。默认情况下,在该请求的Request / Response过程都会受断点控制,即在Request数据发送到的服务端之前会被暂停,在Response数据发送到客户端之前也会被暂停。可以从Charles菜单栏 -> Proxy -> Breakpoint Settings中编辑断点的参数。比如,只需要对Response过程加断点,可以将Request的勾选状态取消。图示如下:

    在断点状态下,可以预览和修改请求的中间数据,之后点解Execute按钮即可继续执行请求。

    五、数据修改

    RewriteBreakpoint Editing都可以起到修改请求数据的作用。

    1. Rewrite

    在Charles菜单栏 -> Tools -> Rewrite中可以开启Rewrite功能,点击Add按钮可以添加一条设置,并可以在右侧的LocationsRules中分别添加要Rewrite的请求路径和Rewrite规则。图示如下:

    Rewrite适合应用于对请求的批量和长期修改,对请求数据影响较大(测试结束后经常忘记去掉规则)。所以,在一些轻量级的数据修改场景中,我经常结合Breakpoint功能修改数据。

    2. Breakpoint Editing

    结合断点功能,可以很好的实现临时修改请求的Request / Response数据的需求。为某条请求设置断点后,当该请求发生时,会自动跳到断点窗口。点开Edit Request / Response界面,可以看到中间信息,选择合适的数据格式(HTML、Json等)进行修改。修改完成后,点击Execute按钮即可在终端上看到修改后的的效果。图示如下:

    六、请求重发

    在Charles的请求预览界面中,右键点击某条/组请求,在弹出的选项列表中有RepeatAdvanced Repeat两个选项。图示如下:

    单击Repeat会重发该请求一次,常用于测试服务接口能否正常访问,客户端能否正常收到返回数据等。单击Advanced Repeat会弹出重发参数编辑页面,图示如下:

    在此编辑界面上,可以自定义Iterations(重发次数)、 Concurrency(并发数)和 Repeat(重发延时),常用于对服务接口进行压力测试。

    七、网速模拟

    在Charles菜单栏 -> Proxy -> Throttle Settings中可以启用Throttling(节流)功能,并自定义Locations(受限服务接口)和Throttle Configuration(节流配置)。支持对Throttle preset(预置的数据传输方式)、Bandwidth(带宽) Utilisation(利用比率)、 Round-trip latency(往返延迟)、MTU(最大传输单元) Reliability(可靠性) Stability(稳定性)等参数进行编辑。其中,在Throttle preset支持模拟3G/4G网络环境。图示如下:

    使用Throttle功能,可以方便地排插因为若网而导致的bug,而这类bug在线上很容易出现,而且很难排查复现。


    小编微信:可加并拉入《QiShare技术交流群》。

    关注我们的途径有:
    QiShare(简书)
    QiShare(掘金)
    QiShare(知乎)
    QiShare(GitHub)
    QiShare(CocoaChina)
    QiShare(StackOverflow)
    QiShare(微信公众号)

    推荐文章:
    初探TCP
    初探IP、UDP
    iOS 多线程之线程安全
    iOS 多线程之GCD
    iOS 多线程之NSOperation
    iOS 多线程之NSThread
    iOS Winding Rules 缠绕规则
    奇舞周刊

    展开全文
  • iOS笔记059 - 网络总结

    2019-07-31 14:19:27
    网络 基本概念 客户端:client 服务器:server 请求:request 响应:response 过程 ...iOS,Android 服务器(后端) 后台 Java、PHP、.NET 远程服务器-面向所有用户(上线) 本地服务器-面向公司内...
  • 客户端:client服务器:server请求:request响应:response过程 客户端 -> 发送请求 -> 服务器(连接数据库)服务器 -> 发送响应 -> 客户端客户端(移动端) 前段(前台)iOS,Android服务器(后端) 后台Java、...
  • 网络总结

    2016-03-17 14:05:18
    基本概念HTTP通信iOS中常用的HTTP请求方式HTTP 实践 - NSURLConnection(了解即可)简单登陆界面解析JSONIOS中JSON解决方案苹果自带的movie播放器字典转模型框架设计框架需要考虑的问题解析XMLXSXMLParserGDataXML解决...
  • Charles其实是一种代理服务器,通过将自己设置成系统(电脑或者浏览器)的网络代理服务器,然后截取请求请求结果打到分析抓包的目的. Charles的主要功能: (1)截取Http 和 Https 网络封包。 (2)支持重发...
  • Charles(青花瓷抓包工具)使用教程

    千次阅读 2019-10-08 16:00:59
    三、主要功能使用 (1)初步认识 Charles 提供两种查看封包的视图, “Structure” 和 “Sequence”。...请求多了有些时候会看不过来,Charles 提供了一个简单的 Filter 功能,可以输入关键字来快速筛选出 UR...
  • Charles

    2020-07-15 18:22:01
    Charles (HTTP代理服务器) HTTP监视器,反转代理服务器,当浏览器连接... 主要功能 支持SSL代理。可以截取分析SSL的请求。...可以模拟慢速网络以及等待时间(latency)较长的请求。 支持AJAX调试。可以自动将jso.
  • 零散知识点

    2019-07-11 11:37:39
    IOS armv Armv6:iPhone 2G/3G、ipod1G/2G Armv7:iPhone3GS/4/4s、ipod3G/4G、ipad1G/2G/3G Armv7s:iPhone5 URL中含有% 当你的接口中含有%22时你要将其替换为\",否则客户端是无妨访问。你将含有%22的接口...
  • Charles其实是一款代理服务器,通过过将自己设置成系统(电脑或者浏览器)的网络访问代理服务器,然后截取请求请求结果达到分析抓包的目的。该软件是用Java写的,能够在Windows,Mac,Linux上使用。安装Charles的...
  • 相信大家对<img>这标签一定再熟悉不过了,然而你熟悉的src后边跟的那个文件一定是一个外部文件吧?... <...无疑都给页面增加了一个请求,因为它们都是把a.gif作为一个外部文件链接的。那么...
  • app测试 面试题

    千次阅读 2019-11-06 10:00:46
    App 测试 1. 简述 Android 四大组件及生命周期? Android 的四大组件包括:Activity(活动)、Service(服务)、 BroadcasReceiver、(广播) ContentProvider(内容提供者) 2. 当点击 APP 图标启动程序,...
  • 前段时间公司需要跟百度聚屏联调,他们的接口数据都是通过protobuf封装的; 为此,我废了好大的脑子,毕竟开局一个文档(参数名和实际给我的参数名都不一致),剩下全靠摸索; 弄懂了之后,其实也没这么复杂。...
  • Charles安装与使用

    2019-10-12 19:47:29
    Charles是一款代理服务器,通过将自己设置成系统(电脑或者浏览器)的网络访问代理服务器,然后截取请求请求结果进行分析抓包。该软件是用Java写的,能够在Windows,Mac,Linux上使用。安装Charles的时候要先装好...
  • Charles是我最近发现的特别好用工具,相信测试工程师都比较熟悉,但作为新手的前端开发... 断点调试(请求前的断点和响应后的断点) 模拟弱网(Chrome也可以做到,但Charles更精确) APP端调试 映射本地资源 接...
  • 1.1.什么是3G、4G Ÿ第三代移动通信技术(3rd-Generation),速率一般在几百Kbps,较之前的2G和2.5G在数据传输速度上有很大提升。 Ÿ第四代移动通信技术(4th-Generation),速度可达到100Mbps以上,几乎可以满足...
  • android基础知识

    2019-06-24 18:33:43
    1.1.什么是3G、4G Ÿ第三代移动通信技术(3rd-Generation),速率一般在几百Kbps,较之前的2G和2.5G在数据传输速度上有很大提升。 Ÿ第四代移动通信技术(4th-Generation),速度可达到100Mbps以上,几乎可以满足...
1 2 3 4 5 ... 7
收藏数 124
精华内容 49
关键字:

4g请求网页乱码 ios