我正在尝试使用iOS中的multi-part form encoding
上传文字。
我做了什么:
我已尝试通过ios Upload Image and Text using HTTP POST。
中提供的信息问题:
我把登录服务器端,这是我从IOS App收到的内容。
key
名称没问题。但是,我收到的value
为null
"443" "POST" "/api/private/json/" "content=null&scope=null&action=null&documentname=null&apikey=null"
我的代码:
NSMutableDictionary *params = [NSMutableDictionary new];
[params setObject:@"XXXXX" forKey:@"apikey"];
[params setObject:@"DataAPI" forKey:@"scope"];
[params setObject:@"push" forKey:@"action"];
[params setObject:docName forKey:@"documentName"];
[params setObject:content forKey:@"content"];
[params setObject:authToken forKey:@"authtoken"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPShouldHandleCookies:NO];
[request setTimeoutInterval:30];
[request setHTTPMethod:@"POST"];
// set Content-Type in HTTP header
NSString *boundary = @"V2ymHFg03ehbqgZCaKO6jy";
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];
NSMutableData *body = [NSMutableData data];
// add params (all params are strings)
for (NSString *param in params) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", param] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", [params objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
// setting the body of the post to the reqeust
[request setHTTPBody:body];
NSString *myString = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
NSLog(@"%@",myString);
// set the content-length
NSString *postLength = [NSString stringWithFormat:@"%d", [body length]];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
// set URL
[request setURL:url];
NSURLResponse *response;
NSData *POSTReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSString *theReply = [[NSString alloc] initWithBytes:[POSTReply bytes] length:[POSTReply length] encoding: NSASCIIStringEncoding];
NSLog(@"Reply: %@", theReply);
我无法理解这个问题,无论是来自服务器端还是来自我的代码。
感谢您分享您的答案。
答案 0 :(得分:1)
您没有附加终止边界。
此:
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
应该是这样的:
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
修改强>
你实际上缺少了一些东西。您没有为数据设置内容类型,而且您缺少一些新行。
你的循环应如下所示:
for (NSString *param in params) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", param] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", [params objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:@"\r\n\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
<强> EDIT2:强>
以下是正确处理相同请求的服务器端代码示例:
#!/usr/bin/env python
import web
urls = ("/", "Index")
app = web.application(urls, globals())
class Index(object):
def POST(self):
x = web.input()
print x
print x['apikey']
print x['scope']
return 'success'
if __name__ == "__main__":
app.run()
输出:
<Storage {'scope': u'asd', 'apikey': u'123\r\n'}>
123
asd
127.0.0.1:60044 - - [02/Dec/2013 15:02:55] "HTTP/1.1 POST /" - 200 OK
示例控制台应用。您可以使用clang编译 - clang -framework Foundation test_post.m -o test_post
#import <Foundation/Foundation.h>
@interface Uploader : NSObject <NSURLConnectionDataDelegate>
@property (nonatomic, strong) NSDictionary *parameters;
@property (nonatomic, strong) NSURLConnection *connection;
@end
@implementation Uploader
- (id)init {
if (self = [super init]) {
}
return self;
}
- (NSMutableURLRequest*)createRequest {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:@"http://localhost:8080/"]];
[request setHTTPMethod:@"POST"];
NSString *boundary = @"0xB0un9ArY";
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request addValue:contentType forHTTPHeaderField:@"Content-Type"];
[request setValue:@"1.0" forHTTPHeaderField:@"MIME-Version"];
[request setValue:@"keep-alive" forHTTPHeaderField:@"Connection"];
NSMutableData *body = [NSMutableData data];
for (NSString *key in [self.parameters allKeys]) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", (self.parameters)[key]] dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
return request;
}
- (void)upload {
NSMutableURLRequest *request = [self createRequest];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (self.connection) [self.connection start];
}
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response {NSLog(@"connection:didReceiveResponse: %@", response);}
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data {NSLog(@"connection: didReceiveData: %@", data);}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error {NSLog(@"connection: didFailWithError: %@", error);}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection { NSLog(@"connectionDidFinishLoading:"); }
@end
int main(int argc, char *argv[])
{
@autoreleasepool {
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
Uploader *uploader = [[Uploader alloc] init];
uploader.parameters = @{@"apikey": @"123", @"scope": @"asd"};
[uploader upload];
[runLoop run];
}
return 0;
}
答案 1 :(得分:1)
这应该解决它:
而不是:
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
写
[body appendData:[[NSString stringWithFormat:@"--%@--", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
(终止CRLF是可选的)
请注意如果你写这个:
for (NSString *param in params) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", param] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", [params objectForKey:param]] dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:@"\r\n\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
在边界定界符之前的所有内容,例如\r\n--<boundary>
在概念上属于数据,例如到参数值。
同样,“破折号边界”(CRLF
)的前面--<boundary>
属于分隔符。
从概念上讲,第一个分隔符也必须以CRLF开头:
`CRLF--<boundary>`
然而,似乎NSURLConnection已经在消息头之后放置了一个CRLF 。所以我们最终得到了这个:
Content-Type: multipart/form-data; boundary="xyz"CRLF
<other header>CRLF
CRLF <-- added by NSURLConnection, which is debatable if this is correct
... multipart body starts here
服务器应忽略在标题之后的任何字节和多部分开始之前的。这种垃圾称为preamble
:
Content-Type: multipart/form-data; boundary="xyz"CRLF
<other header>CRLF
<preamble bytes>CRLF--xyz
^~~~~~~~~ delimiter
....
例如, preamble
可能为空,也可能包含任意数量的CRLF。
body-part
由MIME标题和部分正文数据组成,位于边界之后,但严格来说不是立即:
<preamble-bytes>CRLF--xyz<transport-padding>CRLF<body-part>
^~~~~~~~~ delimiter ^~~~~~~~~~~ MIME headers and data
其中<transport-padding>
是任意数量的空格或水平制表符,也就是说,它可能为空。
这一切都意味着我们应该能够使用以下行作为非终止定界符(对于第一个和任何后续的非终止边界定界符)加上CRLF:
[body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
然后紧随其后的body-part
(从标题开始,然后是数据):
[body appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@", (self.parameters)[key]] dataUsingEncoding:NSUTF8StringEncoding]];
这四行可以在每个参数的循环中使用。
可以按如下方式添加终止分隔符:
[body appendData:[[NSString stringWithFormat:@"\r\n--%@--", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
终止CRLF是可选的。最后一个CRLF之后的任何字节都属于epilogue
,服务器将忽略该字节。
见:RCF 2046 http://www.ietf.org/rfc/rfc2046.txt。
答案 2 :(得分:0)
NSURL *url = [NSURL URLWithString:@"http://210.7.64.98/360videos/webservices/devicetoken.php"];
NSDictionary *postDict = [NSDictionary dictionaryWithObjectsAndKeys:devToken1, @"token",
@"iphone", @"device_type", nil];
NSData *postData = [self encodeDictionary:postDict];
// Create the request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:[NSString stringWithFormat:@"%d", postData.length] forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Peform the request
NSURLResponse *response;
NSError *error = nil;
NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (error) {
// Deal with your error
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSLog(@"HTTP Error: %d %@", httpResponse.statusCode, error);
return;
}
NSLog(@"Error %@", error);
return;
}
NSString *responeString = [[NSString alloc] initWithData:receivedData
encoding:NSUTF8StringEncoding];
NSLog(@"token Response : %@",responeString);
});
//这里是编码方法