Using NSOutputStream to POST to url
-
17-06-2021 - |
题
So all I want to do is send a POST request to a url. Now I tried using NSURLRequest/NSURLConnection, but was having problems with that and decided to move to a lower level, also because I want to send large files and thought dealing directly with streams might be better. But the output stream delegate never seems to be called, and I can't seem to find examples using NSOutputStream's initWithURL
.
NSURL *url = [NSURL URLWithString:NSString stringWithFormat: @"http://url"];
self.outputStream = [[NSOutputStream alloc] initWithURL:url append:NO];
[outputStream retain];
[outputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
It seems that the outputStream is null after the init, which I can't understand because my url is a valid url--I can ping it from the terminal and send data from other sources. Am I doing something wrong, or can anyone tell me how to write a POST request to a URL using streams? Thanks.
解决方案
You cannot use NSOutputStream
to send a POST request to a HTTP server.
The good method is to create a NSMutableURLRequest
and provide that request with a HTTPBodyStream
then create a NSURLConnection
to send the request.
The HTTPBodyStream
is an NSInputStream
the request will read the body from. You may initialize it with a NSData
object or with the contents of a file.
If you want to provide a custom content (for example, you want to upload a file as part of a multipart/form-data
request), you may need to subclass NSInputStream
. In such case, I suggest you to have a look at How to implement CoreFoundation toll-free bridged NSInputStream subclass, which explains how to address an issue that occurs when using custom input streams with NSURLConnection
. Or you may use ASIHTTPRequest which provides multipart HTTP requests out of the box.
其他提示
Yes, you can send the HTTP GET/POST request using NSOutputStream.
1.make & open your stream.
2.when the stream is ready to write, the NSStreamEventHasSpaceAvailable
event will be send in method:
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
https://developer.apple.com/documentation/foundation/nsstreamdelegate/1410079-stream?language=objc
3.make a CFHTTPMessageRef
& and write the data.
code like this:
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
switch (eventCode) {
case NSStreamEventOpenCompleted:{
//
}
break;
case NSStreamEventHasSpaceAvailable:{
[self sendHTTPMessage];
}
break;
default:{
//
}
break;
}
- (void)sendHTTPMessage{
//create a http GET message
CFStringRef requestMethod = (CFStringRef)CFAutorelease(CFSTR("GET"));
CFHTTPMessageRef httpRequest = (CFHTTPMessageRef)CFAutorelease(CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, (__bridge CFURLRef)yourURL,kCFHTTPVersion1_1));
//set HTTP header
CFHTTPMessageSetHeaderFieldValue(httpRequest, (__bridge CFStringRef)@"Host", (__bridge CFStringRef)@"yourhost.com");
CFHTTPMessageSetHeaderFieldValue(httpRequest, (__bridge CFStringRef)@"Connection", (__bridge CFStringRef)@"close");
//set HTTP Body
...
//let's send it
CFDataRef serializedRequest = CFHTTPMessageCopySerializedMessage(httpRequest);
NSData *requestData = (__bridge_transfer NSData *)serializedRequest;
[self.outStream write:requestData.bytes maxLength:requestData.length];
[self.outStream close];
}
Remember, the key point is converting CFHTTPMessageRef to bytes to write.