2019-07-04 19:29:46 georgehenrywilliam 阅读数 383

https://www.cnblogs.com/louzhuhaha/p/3633402.html

ios 使用AFNetWorking 但是将form-data加入头之后,服务器看到传入的参数是空,结果网上翻了半天资料,说是ASI可以的,但是无奈,这个库太老了,并且也尝试了并没有成功,下面载自大神的博客了,将post改为put使用底层的 实现的。

iOS网络请求之multipart/form-data提交数据

multipart/form-data表单数据
在http网络请求中,post没有请求长度的限制,因为post把数据放在了body中,而不是像Get一样放在了浏览器的地址栏中(可以这么理解),
所以相对安全
POST有两种方式
第一种直接把数据放在body中,用contentType来区分类型是text还是json或者是别的什么数据。这个最简单,不做赘述。
第二种是表单的形式,通过boundaries来区分放置的是那些数据,很像一个字典,用K,V放置对象。
参考POST表单数据,这是摘自网上的一段Http请求代码

POST /upload_file/UploadFile HTTP/1.1 
Accept: text/plain, */* 
Accept-Language: zh-cn 
Host: 192.168.29.65:80 
Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6
User-Agent: Mozilla/4.0 (compatible; OpenOffice.org) 
Content-Length: 424 
Connection: Keep-Alive -----------------------------7d33a816d302b6 
Content-Disposition:form-data; 
name="userfile1"; 
filename="E:\s"Content-Type: 
application/octet-stream abbXXXccc 
-----------------------------7d33a816d302b6 

Content-Disposition: form-data; 

name="text1" foo 

-----------------------------7d33a816d302b6 <这里分割线多了两个->

Content-Disposition: form-data; 

name="password1" bar 

-----------------------------7d33a816d302b6--  <这里分割线的前端和末尾多了两个-,表明数据的结束>

大概架构就是这样,下面直接上一个测试代码:

POST_BOUNDS 是我顶一个一个字符串 可以定义你喜欢的任意值

复制代码

 1 -(void)multiPartPost:(NSDictionary *)dicData{
 2     
 3 
 4     NSURL *url = [NSURL URLWithString:@"http://192.168.1.112:8080/TestSerlvet/interfaces"];
 5     NSMutableString *bodyContent = [NSMutableString string];
 6     for(NSString *key in dicData.allKeys){
 7         id value = [dicData objectForKey:key];
 8         [bodyContent appendFormat:@"--%@\r\n",POST_BOUNDS];
 9         [bodyContent appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];
10         [bodyContent appendFormat:@"%@\r\n",value];
11     }
12     [bodyContent appendFormat:@"--%@--\r\n",POST_BOUNDS];
13     NSData *bodyData=[bodyContent dataUsingEncoding:NSUTF8StringEncoding];
14     NSMutableURLRequest *request  = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
15     [request addValue:[NSString stringWithFormat:@"multipart/form-data;boundary=%@",POST_BOUNDS] forHTTPHeaderField:@"Content-Type"];
16     [request addValue: [NSString stringWithFormat:@"%zd",bodyData.length] forHTTPHeaderField:@"Content-Length"];
17     [request setHTTPMethod:@"POST"];
18     [request setHTTPBody:bodyData];
19     NSLog(@"请求的长度%@",[NSString stringWithFormat:@"%zd",bodyData.length]);
20     __autoreleasing NSError *error=nil;
21     __autoreleasing NSURLResponse *response=nil;
22     NSLog(@"输出Bdoy中的内容>>\n%@",[[NSString alloc]initWithData:bodyData encoding:NSUTF8StringEncoding]);
23     NSData *reciveData= [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
24     if(error){
25         NSLog(@"出现异常%@",error);
26     }else{
27         NSHTTPURLResponse *httpResponse=(NSHTTPURLResponse *)response;
28         if(httpResponse.statusCode==200){
29             NSLog(@"服务器成功响应!>>%@",[[NSString alloc]initWithData:reciveData encoding:NSUTF8StringEncoding]);
30             
31         }else{
32             NSLog(@"服务器返回失败>>%@",[[NSString alloc]initWithData:reciveData encoding:NSUTF8StringEncoding]);
33             
34         }
35         
36     }
37 }

 

2019-02-02 09:37:59 gfdhjf 阅读数 143
               

http://hi.baidu.com/yesterdayfei/item/d7fd77713a410222d7a89c21

首先我们得知道,ios是可以将数据传送给其它网页的,不管是什么开发的网站,如PHPJSP ASP ASP.net

原理都是一样的。那么现在我们就来讲讲如何将数据通过post方法传送给网站。相信稍微了解网站开发的朋友都对post不陌生

在ios中给网站送数据一般分为以下几个步骤

1.创建一个指向你需要传数据的网站的NSURL

2.将你要传送的数据设好编码格式

3.创建一个URL请求,如NSMutableURLRequest

4.定义你要提交的内容的类型

5.设定你的提交方法,我们这里用post

6.将你的数据加载到请求中

7.用你的请求建立URL连接

 

下面我有两个实例,分别为传送普通表单以及上传图片

    NSURL *muUrl=[NSURL URLWithString:@"http://192.168.1.101/Test/web/index.php"];//建立URL
    NSMutableURLRequest *myRequest=[NSMutableURLRequest requestWithURL:muUrl];//创建一个指向目的网站的请求
    NSString *myBoundary=@"0xKhTmLbOuNdArY";//这个很重要,用于区别输入的域
    NSString *myContent=[NSString stringWithFormat:@"multipart/form-data;boundary=%@",myBoundary];//意思是要提交的是表单数据
    
    [myRequest setValue:myContent forHTTPHeaderField:@"Content-type"];//定义内容类型
    
    NSMutableData * body=[NSMutableData data];//这个用于暂存你要提交的数据
    //下面开始增加你的数据了

   //我这里假设表单中,有两个字段,一个叫user,一个叫password

//字段与字段之间要用到boundary分开

    [body appendData:[[NSString stringWithFormat:@"\n--%@\n",myBoundary] dataUsingEncoding:NSUTF8StringEncoding]];//表示开始
    [body appendData:[[NSString stringWithString:@"Content-Disposition:form-data;name='user'\n\n"] dataUsingEncoding:NSUTF8StringEncoding]];//第一个字段开始,类型于<input type="text" name="user">
    [body appendData:[[NSString stringWithString:@"leve"] dataUsingEncoding:NSUTF8StringEncoding]]; //第一个字段的内容,即leve
    
    [body appendData:[[NSString stringWithFormat:@"\n--%@\n",myBoundary]dataUsingEncoding:NSUTF8StringEncoding]];//字段间区分开,也意味着第一个字段结束
    
    [body appendData:[[NSString stringWithString:@"Content-Disposition:form-data;name='password'\n\n"]dataUsingEncoding:NSUTF8StringEncoding]];//第二个字段开始,<input type="text" name="password">
    [body appendData:[[NSString stringWithString:@"tan"]dataUsingEncoding:NSUTF8StringEncoding]];//第二个字段的内容
    [body appendData:[[NSString stringWithFormat:@"\n--%@--\n",myBoundary]dataUsingEncoding:NSUTF8StringEncoding]];//结束
    
    [myRequest setHTTPMethod:@"POST"];//定义方法为post.所以如果在PHP端接收的话,以$_POST["user"],$_POST["password"]结收数据
    [myRequest setHTTPBody:body];//将内容加载到请求中
    
    NSData *respondse=[NSURLConnection sendSynchronousRequest:myRequest returningResponse:nil error:nil];//创建连接
    
    NSString * myGet=[[NSString alloc] initWithData:respondse encoding:NSUTF8StringEncoding];//接收数据

 

注意事项:上面有两个字段,第一个[body appendData:[[NSString stringWithString:@"Content-Disposition:form-data;name='user'\n\n"] dataUsingEncoding:NSUTF8StringEncoding]]是这样的。要注意的是,在name='user'\n\n这里,这里一定是两个或以上“\n”.否则将出现接收不到数据


           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

2016-09-09 15:12:20 kws959844005 阅读数 16700
表单上传呢一般是当要上传图片的时候用的网络请求方式。上传http post请求的表单格式是这样的
Content-type: multipart/form-data, boundary=qwerdf  
  
--<span style="font-family: Arial, Helvetica, sans-serif;">qwerdf</span>
  
content-disposition: form-data; name="field1"  
  
i will upload head!  
--<span style="font-family: Arial, Helvetica, sans-serif;">qwerdf</span>
  
content-disposition: form-data; name="pic"; filename="head.png"  
Content-Type: image/png  
  
... contents of boris.png ...  
--<span style="font-family: Arial, Helvetica, sans-serif;">qwerdf</span>-- 


格式是固定的,错了不会上传成功的,而且注意的是图片上传的时候name 和filename 都是有双引号的 而Content-Type 是没有双引号的 而且结尾要以  --   表示表单结束

我们今天要讲的是AFNetworking表单上传,AFN呢帮我们吧表单的格式都封装好了,可以省掉很多的麻烦,灰常的好用,下面我们说说AFN怎么上传图片

首先。。。。。。。。引入头文件啦

第一步 创建AFN管理者,设置一些属性

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = 20;
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"multipart/form-data", @"application/json", @"text/html", @"image/jpeg", @"image/png", @"application/octet-stream", @"text/json", nil];
    第二步 调用AFN的上传图片的方法
</pre><pre name="code" class="objc">[manager POST:url parameters:newLowKeyDic constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        
//利用for循环上传多张图片
        int i = 1;
        for (UIImage * image in self.photoselectVC.images) {
//把图片转换为二进制流
            NSData *imageData = UIImagePNGRepresentation(image);
//按照表单格式把二进制文件写入formData表单
            [formData appendPartWithFileData:imageData name:@"upLoad" fileName:[NSString stringWithFormat:@"%d.png", i] mimeType:@"image/png"];
            
            i++;
            
        }
        
    } success:^(NSURLSessionDataTask *task, id responseObject) {
        NSLog(@"发送成功");
       
        NSLog(@"responseObject == %@", responseObject);
        
        
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
       
        NSLog(@"发送失败");
    }];


是不是很简单呢,这种方法很大众化,毕竟自己写的比较麻烦的,而且表单的格式是非常严格的 每个换行都是不能被忽略的,所以我还是建议一些新手们用AFN进行上传图片啊 等等,当然如果你们感觉AFN的一些功能不能满足你们,可以自己创建表单上传喽。






每周一段

“人们常说左眼跳财右眼跳灾。那我两眼一起跳是什么意思?“,”说明你的人身意外险快起作用了“。







2019-05-29 00:55:04 dickdick111 阅读数 194

中山大学数据科学与计算机学院本科生实验报告

(2019年春季学期)


一、实验题目

IM聊天工具

二、实现内容

  • 用户登陆后拉取用户信息
  • 上传用户头像,multipart/form-data图片上传
  • 修改用户个人详情,与服务器交互

三、实验结果

1. 用户登陆后拉取用户信息

用户登陆成功后,后台仅会返回成功的提示,需要客户端再次进行网络请求来获取这个用户的信息。之前我们的做法是固定的定义UserModel,这样子无法获取更新后的信息,只是能得到这个用户注册时的信息,再他修改个人详情后无法动态更新。这周由我来通过网络请求来动态获取用户的信息。

// 获取用户的信息
-(void) getInfo{
    AFHTTPSessionManager *manger = [AFHTTPSessionManager manager];
    // 定义url
    NSString *url = @"http://172.18.32.97:8000/account/info";
    // 定义成功回调函数
    [manger GET:url parameters:nil progress:nil
        success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            NSLog(@"getInfo success");
            self.loginUser = [[UserModel alloc] 
                             initWithProperties:responseObject[@"data"][@"Username"] 
                              NickName:responseObject[@"data"][@"Nickname"]
                              RemarkName:responseObject[@"data"][@"Username"]
 							  Gender:responseObject[@"data"][@"Gender"]
                              Birthplace:responseObject[@"data"][@"Region"]
                              ProfilePicture:@"peppa"];
    }
        failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            NSLog(@"getInfo fail");
            NSLog(error.localizedDescription);
    }];
}

当成功获取后,将UserModel初始化为从服务器获取的信息。

该函数在用户成功登陆后使用。

if([result[@"state"] isEqualToString:@"ok"])
{
    NSLog(@"login success");
    
    // 登陆成功后,获取用户的个人信息
    [self getInfo];
    
    // ···
}
else
{
    NSLog(@"login fail");
}

2. 读取图像后显示,上传用户头像,multipart/form-data图片上传

在上周,我已经完成了图片从图库的读取,但仍未能更新在tableview中。这周经过仔细的查看,发现是因为我tableview的数据源没有更新为图库读取出来的信息,所以不能更新成功。这里我新定义一个ImageView来存储图库中读取的图片,当回调函数调用的时候,就通知tableview要使用我这个imageView来进行显示。

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *) info{
    // 定义一个newPhoto,用来存放我们选择的图片。
    UIImage *newPhoto = [info objectForKey:@"UIImagePickerControllerEditedImage"];
	// NSLog(urlStr);
    [self dismissViewControllerAnimated:YES completion:nil];
    self.User.ProfilePicture = @"image";
    UIImageView *imageView = [[UIImageView alloc] initWithImage:newPhoto];
    self.head = imageView;
    [self.tableView reloadData];
    
    // 上传到云端
    [[UserManager getInstance] uploadImage:@"/account/info/avatar" withImage:newPhoto];   
}

完成显示后,下一步要进行的就是上传服务器的工作。这里服务器提供的接口是需要上传form-data/multipart的文件,这与其他个人信息改变有些区别,不是简单的键值对。这里我使用到了AFNetworking的第三方网络开源工具库。

这里有几个关键的步骤:

  • 定义session 设置为multipart/form-data
  • 处理url,定义好api
  • 将UIImage图片转成NSData
  • 将NSData加入到formData后就可以执行post请求
  • 处理上传结果回调
// 上传图片到服务器
-(void) uploadImage:(NSString* )path withImage:(UIImage* )image
{
    AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
    [session.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
    
    // 处理url
    NSString* serverDomain = @"http://172.18.32.97:8000";
    NSString* urlString = [serverDomain stringByAppendingString:path];
    NSLog(urlString);
    [session POST:urlString parameters:nil constructingBodyWithBlock:
     ^(id<AFMultipartFormData> _Nonnull formData){
        // 图片转data
        NSData *data = UIImagePNGRepresentation(image);
        [formData appendPartWithFileData :data name:@"file" fileName:@"iName.png"
                                 mimeType:@"multipart/form-data"];
    } progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject){
        NSLog(@"uploadImage success");
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error){
        NSLog(@"uploadImage fail");
        NSLog(error.localizedDescription);
    }];
}

实现效果图:

修改前
在这里插入图片描述

修改后

4

3. 修改用户个人详情,与服务器交互

修改用户个人详情,包括修改用户的昵称,性别,地区的信息。这些都是可以通过键值对来进行修改,比修改图片要容易,这里利用tableview的选择函数进行判断,修改的是哪一个内容,然后再根据这个内容选择不同的api进行修改。

// 上传到云端
if ([str isEqualToString:@"昵称"])
    [[UserManager getInstance] modifyInfo:@"Nickname" withValue:self.User.NickName];
else if ([str isEqualToString:@"性别"])
    [[UserManager getInstance] modifyInfo:@"Gender" withValue:self.User.Gender];
else if ([str isEqualToString:@"地区"])
    [[UserManager getInstance] modifyInfo:@"Region" withValue:self.User.Birthplace];

modifyInfo函数

  • 定义参数
  • 定义handler
  • 定义api
  • 使用之前实现的SessionHelper工具类进行put请求,修改用户对应属性的值
// 根据要修改的属性attr,与修改后的值value来调用网络api
-(void) modifyInfo:(NSString *)attr withValue:(NSString *)value
{
    void (^modifyInfoEvent)(id) = ^void (id object)
    {
        NSDictionary *result = object;
        if([result[@"state"] isEqualToString:@"ok"])
        {
            NSLog(@"modifyInfo success");
        }
        else
        {
            NSLog(result[@"msg"]);
            NSLog(@"modifyInfo fail");
        }
    };
    NSString *params = [[NSString alloc] initWithFormat:@"value=%@", value];
    NSString *api = [[NSString alloc] initWithFormat:@"/account/info/%@", attr];
    NSLog(api);
    NSLog(params);
    [SessionHelper sendRequest:api method:@"put" parameters:params handler:modifyInfoEvent];
}

SessionHelper

#import "SessionHelper.h"

NSString* const SERVER_DOMAIN = @"http://118.89.65.154:8000";

@implementation SessionHelper

+ (void)sendRequest:(NSString*)path method:(NSString*)method parameters:(NSString*)parameters handler:(void(^)(id))handler
{
    //NSString* serverDomain = @"http://172.18.32.97:8000";
    //NSString* serverDomain = @"http://118.89.65.154:8000";
    NSString* urlString = [SERVER_DOMAIN stringByAppendingString:path];
    NSURL *url = [NSURL URLWithString:urlString];
    
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
    
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
    
    [urlRequest setHTTPMethod:method];
    if (![parameters isEqual: @""])
    {
        NSString *params = [[NSString alloc] initWithString:parameters];
        [urlRequest setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
    }
    
    NSURLSessionDataTask *task = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error)
    {
        if(error == nil)
        {
            if(NSClassFromString(@"NSJSONSerialization"))
            {
                NSError *parseError = nil;
                id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
                if(parseError)
                {
                    NSLog(@"parse error: %@", parseError);
                }
                if([object isKindOfClass:[NSDictionary class]])
                {
                    handler(object);
                }
                else
                {
                    NSLog(@"Not dictionary");
                }
            }
        }
        else
        {
            NSLog(@"Network error:%@", error);
        }
    }];
    
    [task resume];
}

@end

实现效果图:

修改前

1

修改后

2

四、实验思考及感想

​ 本周的展示,我们小组也基本把当前的情况说明了一下,进度不错,其中的问题也咨询了字节的工程师,在进行改进或者做一些额外需求加分项。这周我主要的工作是进行网络访问,连接后台修改个人信息等,其中最为难的部分是对于图片的处理,因为之前都是在修改文字比较直观,而到了图片需要转换的格式也不一样。在我与后台的同学互相研究后,终于也实现了上传修改图片等功能。我实现了个上传图片的工具函数,后面做消息传递的时候,发送图片也可以用到,图片问题算是解决了。关于加分项,我们甚至想到了发送视频或者发送语音,这些与后台的交互相信也不简单,留待下一周再进行。

2019-12-24 17:36:05 u012881779 阅读数 30

 做内购支付时,后端需要验证订单支付状态,因为这个校验字符串非常长,所以使用form-data的方式提交表单。

#pragma mark - 内购支付成功后确认

- (void)netApplePayWithTran:(SKPaymentTransaction *)transaction OrderId:(NSString *)orderId {
    NSString *tranID = transaction.transactionIdentifier;
    [[XYStore defaultStore] base64Receipt:^(NSString *base64Data) {
        // base64Data = [GAPublicClass URLEncodedString:base64Data];
        NSMutableDictionary *parms = [NSMutableDictionary dictionary];
        [parms setObject:tranID forKey:@"transactionId"]; // 苹果内购交易ID
        [parms setObject:base64Data forKey:@"payload"]; // 校验体(base64字符串
        [parms setObject:orderId forKey:@"orderId"]; // 订单id
        [self validationPartPost:parms];
    } failure:^(NSError *error) {
        
    }];
}

- (void)validationPartPost:(NSDictionary *)dicData {
    NSString *POST_BOUNDS = @"yxqipayanzheng";
    NSString *tokenStr = [AccountTool sqLoginModel].token;

    NSURL *url = [NSURL URLWithString:[API_DOMAIN_COMMUNITY stringByAppendingString:url_apple_pay]];
    NSMutableString *bodyContent = [NSMutableString string];
    for(NSString *key in dicData.allKeys){
        id value = [dicData objectForKey:key];
        [bodyContent appendFormat:@"--%@\r\n",POST_BOUNDS];
        [bodyContent appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];
        [bodyContent appendFormat:@"%@\r\n",value];
    }
    [bodyContent appendFormat:@"--%@--\r\n",POST_BOUNDS];
    NSData *bodyData=[bodyContent dataUsingEncoding:NSUTF8StringEncoding];
    
    NSMutableURLRequest *request  = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
    [request addValue:[NSString stringWithFormat:@"multipart/form-data;boundary=%@",POST_BOUNDS] forHTTPHeaderField:@"Content-Type"];
    [request setValue:tokenStr forHTTPHeaderField:@"token"];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:bodyData];
    
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [MBProgressHUD hideHUDForView:KWindow animated:YES];
        });
        NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
        NSInteger status = [responseJSON[@"status"] integerValue];
        if (status == 200) {

        }
    }];
    [task resume];
}

TO

iOS里实现multipart/form-data格式上传文件
iOS 上传multipart/form-data格式文件
iOS之网络请求之AFN表单上传之form-data

multipart/form-data

阅读数 22

没有更多推荐了,返回首页