豆瓣客户端(三)发送图文广播

2024-05-26 11:08

本文主要是介绍豆瓣客户端(三)发送图文广播,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这只是一个简单的Demo,功能是调用豆瓣的接口发送图文广播。功能并不齐全,只是为网络编程练练手而已。

首先强调,这里没有用到第三方类库,也没有使用豆瓣的iOS SDK,都是直接用iOS给出的类和接口写的,只有代码是自己的,才真正有一种踏实的感觉。

当然第三方类库也非常好用,而且我也非常尊敬开发者开源共享的精神。


该广播接口的主要内容如下:

URL

shuo/v2/statuses/

HTTP请求方式

POST
’我说‘类型的广播中如果需要附带图片,注意采用multipart/form-data编码方式上传,上传图片大小限制为<3M,仅支持JPEG,GIF,PNG图片,name 是 image

请求参数

  必选 类型及范围 说明
source true string appkey
text true string 广播文本内容
image false bytes 我说的图
rec_title false string 推荐网址的标题
rec_url false string 推荐网址的href
rec_desc false string 推荐网址的描述
rec_image false string 推荐网址的附图url

调用示例

curl "https://api.douban.com/shuo/v2/statuses/" -H "Authorization: Bearer TOKEN"  -F "text=TestText"  -F "image=@upload.png"
分析:

接口:https://api.douban.com/shuo/v2/statuses/

请求方式:POST

请求参数:source(必须,NSString),text(必须,NSString),image(可选,二进制数据)。

请求头:Authorization : Bearer ACCESS_TOKEN


首先是认证授权,不多说。

接着来到发广播界面:


对应SayViewController,下面看看该ViewController的接口部分:

#import <UIKit/UIKit.h>@interface SayViewController : UIViewController <UITextViewDelegate, NSURLConnectionDataDelegate, NSURLConnectionDelegate>
@property (weak, nonatomic) IBOutlet UITextView *myWords_textView; // 广播内容编辑框
@property (weak, nonatomic) IBOutlet UIBarButtonItem *send_buttonItem; // 发送按钮
- (IBAction)sendMyWords:(id)sender; // 发送广播
@property (strong, nonatomic) NSMutableData *responseData; // 发送广播后返回的数据
@end

如果是单纯的发送文字内容则非常简单:

- (IBAction)sendMyWords:(id)sender {[myWords_textView resignFirstResponder];if ([myWords_textView.text isEqualToString:@""]) {UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"发表广播失败"message:@"你输入的广播内容为空"delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];[av show];}else {//  -- 建立URL请求对象 --NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:SEND_BROADCAST_URL]cachePolicy:NSURLRequestReloadIgnoringCacheDatatimeoutInterval:20.0];//  -- 设置HTTP请求方式为POST --[request setHTTPMethod:@"POST"];//  -- 设置HTTP请求的BODY数据 --NSString *paramSource = [NSString stringWithFormat:@"source=%@", API_KEY];NSString *paramText = [NSString stringWithFormat:@"text=%@", myWords_textView.text];NSString *parameters = [NSString stringWithFormat:@"%@&%@", paramSource, paramText];NSMutableData *postData = [[NSMutableData alloc] init];[postData appendData:[parameters dataUsingEncoding:NSUTF8StringEncoding]];[request setHTTPBody:postData];//  -- 设置HTTP请求头部分 --NSString *bearerToken = [NSString stringWithFormat:@"Bearer %@", [OAuthViewController getAccessToken]];[request setValue:bearerToken forHTTPHeaderField:@"Authorization"];//  -- 建立URL连接 --NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];if (connection) {[connection start];}}
}

首先以接口网址初始化请求。

然后设置参数,并编码成二进制数据:

NSString *parameters = [NSString stringWithFormat:@"%@&%@", paramSource, paramText];
[parameters dataUsingEncoding:NSUTF8StringEncoding]

再将其编码好的二进制数据设置为HTTP请求的BODY。

在设置好请求头后,建立URL连接,start即可。

利用NSURLConnection和NSURLConnectionData的委托可以获取返回的数据:

#pragma mark -
#pragma mark NSURLConnection or NSURLConnectionData delegate- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {if (response) {responseData = [[NSMutableData alloc] initWithLength:0];}
}- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {if (data) {[responseData appendData:data];}
}- (void)connectionDidFinishLoading:(NSURLConnection *)connection {NSError *error = nil;NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];NSLog(@"dic = %@", dic);UIAlertView *av = nil;if (!dic || dic[@"code"]) {av = [[UIAlertView alloc] initWithTitle:@"发送失败"message:@"未知错误"delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];}else {av = [[UIAlertView alloc] initWithTitle:@"发送成功"message:@"Congratulations"delegate:nil cancelButtonTitle:@"Good" otherButtonTitles:nil, nil];}[av show];
}- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"发生错误"message:[error localizedDescription]delegate:nilcancelButtonTitle:@"确定" otherButtonTitles:nil, nil];[av show];
}

其中使用responseData来接收返回的数据。

注意responseData是NSMutableData类型,首先如果收到服务器的响应就调用DidReceiveResponse就初始化该变量,但长度为0。

随着服务器不断返回数据,在DidReceiveData的不断调用中补全接收到的数据。

在接收数据完成后调用DidFinishLoading进行处理,如果接收数据失败就调用DidFailWithError作出错处理。

Run一下:


点击发送后,在我的豆瓣中的我的广播中可以看到结果:



真正麻烦的是要实现图文广播,注意这里强调的是不使用第三方类库或者豆瓣给出的SDK。

先看看文档的说明:

’我说‘类型的广播中如果需要附带图片,注意采用multipart/form-data编码方式上传,上传图片大小限制为<3M,仅支持JPEG,GIF,PNG图片,name 是 image
multipart/form-data编码方式,也就是要把各个字段分开分别编码,然后将合起来的二进制数据设置为请求的BODY再POST到服务器。

好吧,我对HTTP协议,报文内容什么的的确了解不多,看来专业课的理论知识还是非常重要的。

在参考了网上一些文章后才大致明白其编码的工作方式,最后参考一下豆瓣SDK中的代码还是解决了该部分的内容。

先给出两篇挺有价值的参考文章:

IOS Post form(data and pic)I

【原】iOS通过http post上传图片(头像是个帅哥来的,感谢这位帅哥的分享)

在参考了豆瓣的SDK的源码后,我大致假设HTTP请求报文内容如下:

Content-type: multipart/form-data, charset=utf-8, boundary=KhTmLbOuNdArY, Authorization=Bearer access_token--KhTmLbOuNdArY
Content-disposition: form-data; name="source"AppKey对应的内容
--KhTmLbOuNdArY
Content-disposition: form-data; name="text"要发送的广播内容
--KhTmLbOuNdArY
content-disposition: form-data; name="image"; filename="WW.jpg"
Content-Type: image/png... contents of WW.jpg ...
--KhTmLbOuNdArY--

其中WW.jpg就是我要POST的一张图片。


下面逐段贴上代码吧:

首先设置好请求头内容(Content-type: multipart/form-data, charset=utf-8, boundary=KhTmLbOuNdArY, Authorization=Bearer access_token)和请求方式为POST。

        //  -- 设置HTTP请求方式和请求头 --// 请求头的内容:// Content-type: multipart/form-data, charset=utf-8, boundary=KhTmLbOuNdArY, Authorization=Bearer access_tokenNSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));CFUUIDRef uuid = CFUUIDCreate(nil);NSString *uuidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(nil, uuid));CFRelease(uuid);NSString *stringBoundary = [NSString stringWithFormat:@"0xKhTmLbOuNdArY-%@",uuidString];NSString *endItemBoundary = [NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary];NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:SEND_BROADCAST_URL]];[request setHTTPMethod:@"POST"];[request setValue:[NSString stringWithFormat:@"multipart/form-data; charset=%@; boundary=%@", charset, stringBoundary] forHTTPHeaderField:@"Content-Type"];NSString *bearerToken = [NSString stringWithFormat:@"Bearer %@", [OAuthViewController getAccessToken]];[request setValue:bearerToken forHTTPHeaderField:@"Authorization"];


然后开始对BODY的内容进行逐段二进制编码:

        //  -- 对要POST的数据进行编码并设置HTTP请求的BODY --// 开头的boundary:// --KhTmLbOuNdArYNSMutableData *postData = [[NSMutableData alloc] init];[postData appendData:[[NSString stringWithFormat:@"--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];// source参数对应的key和内容:// Content-disposition: form-data; name="source"//// AppKey对应的内容NSString *kSource = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"source\"\r\n\r\n"];[postData appendData:[kSource dataUsingEncoding:NSUTF8StringEncoding]];NSString *vSource = [NSString stringWithFormat:@"source=%@", API_KEY];[postData appendData:[vSource dataUsingEncoding:NSUTF8StringEncoding]];// 分割字段内容的boundary:// --KhTmLbOuNdArY[postData appendData:[endItemBoundary dataUsingEncoding:NSUTF8StringEncoding]];// text参数对应的key和内容:// Content-disposition: form-data; name="text"//// 要发送的广播内容NSString *kText = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"text\"\r\n\r\n"];[postData appendData:[kText dataUsingEncoding:NSUTF8StringEncoding]];NSString *vText = myWords_textView.text;[postData appendData:[vText dataUsingEncoding:NSUTF8StringEncoding]];// 分割字段内容的boundary:// --KhTmLbOuNdArY[postData appendData:[endItemBoundary dataUsingEncoding:NSUTF8StringEncoding]];// image参数对应的key和内容:// content-disposition: form-data; name="image"; filename="WW.jpg"// Content-Type: image/png//// ... contents of WW.jpg ...NSString *kImage = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"image\"; filename=\"WW.jpg\"\r\n"];[postData appendData:[kImage dataUsingEncoding:NSUTF8StringEncoding]];NSString *tImage = [NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", @"image/jpeg"];[postData appendData:[tImage dataUsingEncoding:NSUTF8StringEncoding]];UIImage *pickedImage = [UIImage imageNamed:@"WW.jpg"];// NSData *imageData = UIImagePNGRepresentation(pickedImage); // png格式NSData *imageData = UIImageJPEGRepresentation(pickedImage, 0.0); // jpg格式,1.0表示最大压缩,0.0表示图像无压缩[postData appendData:imageData];// 结尾的boundary// --KhTmLbOuNdArY--[postData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];//  -- 设置HTTP的BODY和请求头中的Content-Length --NSString *length = [NSString stringWithFormat:@"%d", [postData length]];[request setValue:length forHTTPHeaderField:@"Content-Length"];[request setHTTPBody:postData];
最后建立URL连接,并通过委托获取服务器回调的数据,代码和上面的发文字广播相同,不再重复。

还是Run一下:


点了发送后,我的广播内容也更新了:


老白出现了,就是WW.jpg对应的图片内容。(看到老白最后倒在实验室含笑而终,Baby Blue音乐一直在唱,既感到欣慰又是心痛啊,永别了,我的老白)


该博客对应的Demo已经上传,欢迎下载交流。由于豆瓣应用的机制:只有添加为该应用的测试用户才可以授权给该应用并登录,所以如果你想运行该应用,可以自己新建一个豆瓣应用,再替换Demo中的DBAPIURL.h中的API_KEY,SECRET_KEY和REDIRECT_URI。或者你留下你豆瓣的uid,让我添加你为该应用的测试用户就可以使用了。



好了,最后小结一下。

主要说说POST数据的方法(不使用第三方类库,尽管它们非常好用)。

如果单纯是POST一些NSString等类型的数据,直接设置参数,再编码为NSData就可以了,例如获取token时:

    NSString *paramClinetID = [NSString stringWithFormat:@"client_id=%@", API_KEY];NSString *paramClientSecret = [NSString stringWithFormat:@"client_secret=%@", SECRET_KEY];NSString *paramRedirectURI = [NSString stringWithFormat:@"redirect_uri=%@", REDIRECT_URI];NSString *paramGrantType = @"grant_type=authorization_code";NSString *paramCode = [NSString stringWithFormat:@"code=%@", authorization_code];NSString *parameters = [NSString stringWithFormat:@"%@&%@&%@&%@&%@", paramClinetID, paramClientSecret, paramRedirectURI, paramGrantType, paramCode];NSMutableData *postData = [[NSMutableData alloc] init];[postData appendData:[parameters dataUsingEncoding:NSUTF8StringEncoding]];


如果要POST的数据中包含了多个字段,并且其中一些数据是图片,音乐等文件数据时,就要使用multi-part/form-data的编码方式了,说到底都是将各个字段的数据编码成二进制数据而已,关键是按报文数据的格式进行二进制数据编码。

最近要做一个将文件POST到服务器的功能,很简单地用ASI实现了,但是始终觉得代码不是自己的心里就不踏实,所以就回来写下豆瓣练练手,最终还是实现了豆瓣POST图片的功能。

另外,我对HTTP协议的了解不多(课程还没讲,而自己又很懒还没去看),所以难免会有许多错漏,希望大家指出错误,让我改正。



---------------------------------------------- 我是分割线 ------------------------------------------------------


昨晚看完了最后一集的绝命毒师,思绪万千,今天就忍不住在博客里写了下来,看代码的人可以忽略。

老白始终让我有一种很亲切的感觉,他的结局我感觉还算欣慰吧,起码他成功地反击了杰克军团,就走了小粉,安排好了家人的一切,并且死在了他最爱的实验室里,最后很安详地倒在了地上,含笑而终。

看见他在摸着实验室的仪器,流露出不舍的表情的时候,相信各位老白的粉丝心里都酸酸的。

好吧,最后仅以一句简单的豆瓣广播向我亲爱的老白说声再见吧。




这篇关于豆瓣客户端(三)发送图文广播的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1004288

相关文章

MYSQL查询结果实现发送给客户端

《MYSQL查询结果实现发送给客户端》:本文主要介绍MYSQL查询结果实现发送给客户端方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql取数据和发数据的流程(边读边发)Sending to clientSending DataLRU(Least Rec

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

Python FastMCP构建MCP服务端与客户端的详细步骤

《PythonFastMCP构建MCP服务端与客户端的详细步骤》MCP(Multi-ClientProtocol)是一种用于构建可扩展服务的通信协议框架,本文将使用FastMCP搭建一个支持St... 目录简介环境准备服务端实现(server.py)客户端实现(client.py)运行效果扩展方向常见问题结

C#使用MQTTnet实现服务端与客户端的通讯的示例

《C#使用MQTTnet实现服务端与客户端的通讯的示例》本文主要介绍了C#使用MQTTnet实现服务端与客户端的通讯的示例,包括协议特性、连接管理、QoS机制和安全策略,具有一定的参考价值,感兴趣的可... 目录一、MQTT 协议简介二、MQTT 协议核心特性三、MQTTNET 库的核心功能四、服务端(BR

C#实现访问远程硬盘的图文教程

《C#实现访问远程硬盘的图文教程》在现实场景中,我们经常用到远程桌面功能,而在某些场景下,我们需要使用类似的远程硬盘功能,这样能非常方便地操作对方电脑磁盘的目录、以及传送文件,这次我们将给出一个完整的... 目录引言一. 远程硬盘功能展示二. 远程硬盘代码实现1. 底层业务通信实现2. UI 实现三. De

ubuntu20.0.4系统中安装Anaconda的超详细图文教程

《ubuntu20.0.4系统中安装Anaconda的超详细图文教程》:本文主要介绍了在Ubuntu系统中如何下载和安装Anaconda,提供了两种方法,详细内容请阅读本文,希望能对你有所帮助... 本文介绍了在Ubuntu系统中如何下载和安装Anaconda。提供了两种方法,包括通过网页手动下载和使用wg

SpringBoot快速搭建TCP服务端和客户端全过程

《SpringBoot快速搭建TCP服务端和客户端全过程》:本文主要介绍SpringBoot快速搭建TCP服务端和客户端全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录TCPServerTCPClient总结由于工作需要,研究了SpringBoot搭建TCP通信的过程

IDEA之MyBatisX使用的图文步骤

《IDEA之MyBatisX使用的图文步骤》本文主要介绍了IDEA之MyBatisX使用,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 目录一、idea插件安装二、IDEA配置数据库连接(以mysql为例)三、生产基础代码一、idea插

使用Python和SQLAlchemy实现高效的邮件发送系统

《使用Python和SQLAlchemy实现高效的邮件发送系统》在现代Web应用中,邮件通知是不可或缺的功能之一,无论是订单确认、文件处理结果通知,还是系统告警,邮件都是最常用的通信方式之一,本文将详... 目录引言1. 需求分析2. 数据库设计2.1 User 表(存储用户信息)2.2 CustomerO

使用Python和PaddleOCR实现图文识别的代码和步骤

《使用Python和PaddleOCR实现图文识别的代码和步骤》在当今数字化时代,图文识别技术的应用越来越广泛,如文档数字化、信息提取等,PaddleOCR是百度开源的一款强大的OCR工具包,它集成了... 目录一、引言二、环境准备2.1 安装 python2.2 安装 PaddlePaddle2.3 安装