cocoahttpserver使用详解(二)


接下来,我们接着去学习如何去接收处理web上传的数据

1 首先我们创建一个

@interface WTZHTTPConnection : HTTPConnection

在这个类中我们用于处理接受文件并存储到app文档

同时不要忘记了设置httpserver的Connectio类

[httpServer setConnectionClass:[WTZHTTPConnectionclass]];

全部的代码如下

.h文件

#define UPLOAD_FILE_PROGRESS @"uploadfileprogress"

#import <Foundation/Foundation.h>
#import "HTTPConnection.h"

@interface WTZHTTPConnection : HTTPConnection
{
	int             dataStartIndex;
	NSMutableArray  *multipartData;
	BOOL            postHeaderOK;
}

- (BOOL) isBeginOfOctetStream;

@end

.m文件

#import "WTZHTTPConnection.h"

@implementation WTZHTTPConnection

- (void)dealloc {
    [multipartData release];
    [super dealloc];
}

    //扩展HTTPServer支持的请求类型,默认支持GET,HEAD,不支持POST
- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)relativePath
{
	if ([@"POST" isEqualToString:method])
	{
		return YES;
	}
	return [super supportsMethod:method atPath:relativePath];
}

    //处量返回的response数据
- (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
{
    return [super httpResponseForMethod:method URI:path];
}

    //处理POST请求提交的数据流(下面方法是改自 Andrew Davidson的类)
- (void)processDataChunk:(NSData *)postDataChunk
{
    NSLog(@"processDataChunk function called");
        //multipartData初始化不放在init函数中, 当前类似乎不经init函数初始化
    if (multipartData == nil) {
        multipartData = [[NSMutableArray alloc] init];
    }

        //处理multipart/form-data的POST请求中Body数据集中的表单值域并创建文件
	if (!postHeaderOK)
	{
            //0x0A0D: 换行符
		UInt16 separatorBytes = 0x0A0D;
		NSData* separatorData = [NSData dataWithBytes:&separatorBytes length:2];

		int l = (int)[separatorData length];
		for (int i = 0; i < [postDataChunk length] - l; i++)
		{
                //每次取两个字节 比对下看看是否是换行
			NSRange searchRange = {i, l};
                //如果是换行符则进行如下处理
			if ([[postDataChunk subdataWithRange:searchRange] isEqualToData:separatorData])
			{
                    //获取dataStartIndex标识的上一个换行位置到当前换行符之间的数据的Range
				NSRange newDataRange = {dataStartIndex, i - dataStartIndex};
                    //dataStartIndex标识的上一个换行位置到移到当前换行符位置
				dataStartIndex = i + l;
				i += l - 1;
                    //获取dataStartIndex标识的上一个换行位置到当前换行符之间的数据
				NSData *newData = [postDataChunk subdataWithRange:newDataRange];
                    //如果newData不为空或还没有处理完multipart/form-data中表单变量值域则继续处理剩下的表单值域数据
				if ([newData length] || ![self isBeginOfOctetStream])
				{
                    if ([newData length]) {
                        [multipartData addObject:newData];
                    }
				}
				else
				{
                        //将标识处理完multipart/form-data中表单变量值域的postHeaderOK变量设置为TRUE;
					postHeaderOK = TRUE;
                        //这里暂时写成硬编码 弊端:每次增加表单变量都要改这里的数值
                        //获取Content-Disposition: form-data; name="xxx"; filename="xxx"
					NSString* postInfo = [[NSString alloc] initWithBytes:[[multipartData objectAtIndex:4] bytes]
                                                                  length:[[multipartData objectAtIndex:4] length]
                                                                encoding:NSUTF8StringEncoding];
                    NSLog(@"postInfo is:%@", postInfo);
					NSArray* postInfoComponents = [postInfo componentsSeparatedByString:@"; filename="];
					postInfoComponents = [[postInfoComponents lastObject] componentsSeparatedByString:@"\""];
                    NSLog(@"postInfoComponents0 :%@",postInfoComponents);
                    if ([postInfoComponents count]<2)
                    {
                        return;
                    }

					postInfoComponents = [[postInfoComponents objectAtIndex:1] componentsSeparatedByString:@"\\"];
                    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
					NSString* filename = [documentPath stringByAppendingPathComponent:[postInfoComponents lastObject]];
                    NSLog(@"filename :%@",filename);
					NSRange fileDataRange = {dataStartIndex, [postDataChunk length] - dataStartIndex};
					[[NSFileManager defaultManager] createFileAtPath:filename contents:[postDataChunk subdataWithRange:fileDataRange] attributes:nil];
					NSFileHandle *file = [[NSFileHandle fileHandleForUpdatingAtPath:filename] retain];
					if (file)
					{
						[file seekToEndOfFile];
						[multipartData addObject:file];
					}

					[postInfo release];
					break;
				}
			}
		}
	}
	else //表单值域已经处理过了 这之后的数据全是文件数据流
	{
		[(NSFileHandle*)[multipartData lastObject] writeData:postDataChunk];
	}

    float uploadProgress = (double)requestContentLengthReceived / requestContentLength;
		//实际应用时 当前类的实例是相当于单例一样被引用(因为只被实例化一次)
	if (uploadProgress >= 1.0) {
		postHeaderOK = NO;
		[multipartData release];
		multipartData = nil;
	}
    [[NSNotificationCenter defaultCenter] postNotificationName:UPLOAD_FILE_PROGRESS object:[NSNumber numberWithFloat:uploadProgress] userInfo:nil];
}

//检查是否已经处理完了multipart/form-data表单中的表单变量
- (BOOL) isBeginOfOctetStream
{
    NSString *octetStreamFlag = @"Content-Type: application/octet-stream";
    NSString *findData = [[NSString alloc] initWithData:(NSData *)[multipartData lastObject] encoding:NSUTF8StringEncoding];

    for (NSData *d in multipartData) {
        NSString *temp = [[[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding] autorelease] ;
        NSLog(@"multipartData items: %@", temp);
    }
        //如果已经处理完了multipart/form-data表单中的表单变量
    if ( findData != nil && [findData length] > 0 )
    {
        NSLog(@"findData is :%@\n octetStreamFlag is :%@", findData, octetStreamFlag);
        if ([octetStreamFlag isEqualToString:findData]) {
            NSLog(@"multipart/form-data 变量值域数据处理完毕");
            [findData release];
            return YES;
        }
        [findData release];
        return NO;
    }
    return NO;

}

@end

主要的代码就在 processDataChunk,我们只需要在这里面处理数据即可

以上代码主要转自github上 https://github.com/willonboy/CocoaHTTPServer---multipart-form-data点击打开链接

大家可以下载源码研究

下章将要讲解 web js代码

cocoahttpserver使用详解(二),布布扣,bubuko.com

时间: 2024-10-12 15:29:45

cocoahttpserver使用详解(二)的相关文章

UINavigationController详解二(转)页面切换和SegmentedController

原文出自:http://blog.csdn.net/totogo2010/article/details/7682433,非常感谢. 1.RootView 跳到SecondView 首先我们需要新一个View.新建SecondView,按住Command键然后按N,弹出新建页面,我们新建SecondView 2.为Button 添加点击事件,实现跳转 在RootViewController.xib中和RootViewController.h文件建立连接 在RootViewController.m

Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)

[Android布局学习系列]   1.Android 布局学习之——Layout(布局)详解一   2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)   3.Android 布局学习之——LinearLayout的layout_weight属性   4.Android 布局学习之——LinearLayout属性baselineAligned的作用及baseline    Layout Parameters(布局参数): 在XML文件中,我们经常看到类似与lay

CSS3中的弹性流体盒模型技术详解(二)

在上一篇文章<CSS3中的弹性流体盒模型技术详解(一)>里,我给大家列出了,从css1到css3各版本中盒子模型的基本元素.本篇我会把余下的属性进行详细讲解. box-pack 作用:用来规定子元素在盒子内的水平空间分配方式 box-pack 语法:box-pack: start | end | center | justify; start 对于正常方向的框,首个子元素的左边缘吸附在盒子的左边框显示 对于相反方向的框,最后子元素的右边缘吸附在盒子的右边框显示 end 对于正常方向的框,最后子

php学习之道:WSDL详解(二)

3.定义服务使用的逻辑消息 当服务的操作被调用时,服务被定义为消息交换.在wsdl文档中,这些消息被定义message元素.这些消息由称之为part元素的部分组成. 一个服务的操作,通过指定逻辑消息的方式来定义.当操作被调用时,逻辑消息被交换.(也就是说,逻辑消息代表了服务的操作)这些逻辑消息,将在网络上传输的数据定义为xml文档.他包含了所有的参数,这些参数是方法调用的一部分.(也就是说,逻辑消息里的参数,是操作对应方法的参数集合) 消息和参数列表:每一个被服务暴露的操作能且仅能有一个输入消息

LinearLayout详解二:从其父类View说起

这个View类说来就话长了,但我们又不得不说,要说呢,就得说的彻底,要让大家看得一清二楚,明明白白.所以我们就从源代码角度来看一个view是如何被加载的吧. 如果大家不知道怎么下载android的源代码,或者说懒得去下载(因为源代码确实比较大,大概有10G)的话,教大家几个取巧的办法: 1.直接在google中输入"android view.java"即可.这种方法成功率非常高,一般android的比较重要的类都能搜到. 2.给大家提供一个人家用于放源码的的git:[email pro

jquery validate 详解二

原文:http://blog.sina.com.cn/s/blog_608475eb0100h3h2.html 这里只是第二篇,前面的内容请参阅上一篇 五.常用方法及注意问题 1.用其他方式替代默认的SUBMIT 1 $().ready(function() { 2 $("#signupForm").validate({ 3 submitHandler:function(form){ 4 alert("submitted"); 5 form.submit(); 6

cocos2dx 启动过程详解二:内存管理和回调

在上一篇的第二部分中,我们有一句代码待解释的: // Draw the Scene void CCDirector::drawScene(void) { -- //tick before glClear: issue #533 if (! m_bPaused) //暂停 { m_pScheduler->update(m_fDeltaTime);   //待会会解释这里的内容 } -- } 这里是一个update函数,经常会写像this->schedule(schedule_selector(X

PopUpWindow使用详解(二)——进阶及答疑

相关文章:1.<PopUpWindow使用详解(一)——基本使用>2.<PopUpWindow使用详解(二)——进阶及答疑> 上篇为大家基本讲述了有关PopupWindow的基本使用,但还有几个相关函数还没有讲述,我们这篇将着重看看这几个函数的用法并结合源码来讲讲具体原因,最后是有关PopupWindow在使用时的疑问,给大家讲解一下. 一.常用函数讲解 这段将会给大家讲下下面几个函数的意义及用法,使用上篇那个带背景的例子为基础. [java] view plain copy pu

HTTPS详解二:SSL / TLS 工作原理和详细握手过程

HTTPS 详解一:附带最精美详尽的 HTTPS 原理图 HTTPS详解二:SSL / TLS 工作原理和详细握手过程 在上篇文章HTTPS详解一中,我已经为大家介绍了 HTTPS 的详细原理和通信流程,但总感觉少了点什么,应该是少了对安全层的针对性介绍,那么这篇文章就算是对HTTPS 详解一的补充吧.还记得这张图吧. HTTPS 和 HTTP的区别 显然,HTTPS 相比 HTTP最大的不同就是多了一层 SSL (Secure Sockets Layer 安全套接层)或 TLS (Transp