gpt4 book ai didi

ios - NSURLSession 将 header 'Connection' 设置为 'Upgrade' 不起作用

转载 作者:行者123 更新时间:2023-12-03 16:57:13 27 4
gpt4 key购买 nike

环境:Mac OS X 10.9、Xcode 5.0.2

我需要为我的迷你 WebSocket 客户端创建一个 HTTP 请求,示例请求:

GET / HTTP/1.1
Host: serverwebsocket.com:10080
Upgrade: websocket
Connection: Upgrade
Origin: http://from.com

我已经使用 NSURLSessionConfiguration 创建了 NSURLSession 并设置了 header ,Wireshark 显示了除 Connection 之外的所有 header 设置,其中 Connection 保持 keep -活着,但不应该。

// Create request based on Sessions

// Create sesson configuretion
NSURLSessionConfiguration* sessionConf = [NSURLSessionConfiguration defaultSessionConfiguration];

// Configure session config
// set header value, detail header websocket on http://learn.javascript.ru/websockets
sessionConf.HTTPAdditionalHeaders = @{@"Upgrade": @"websocket",
@"Connection": @"Upgrage",
@"Origin": @"http://from.com",
@"User-Agent": @"Chrome/36.0.198.5.143"};

// Declare handler block of response
__block void (^handler)(NSData* data, NSURLResponse* response, NSError* error);

handler = ^(NSData* data, NSURLResponse* response, NSError* error)
{
// If receive response from server
if(data)
{
NSString* result = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSLog(@"response data: %@", result);

}
else // something wrong
{
NSString* errorText;

if(error)
{
errorText = [error localizedDescription];
}
else // Generic description
{
errorText = @"Error Interner connection";
}
NSLog(@"Request error: %@",errorText );
}
};


// Create Session
NSURLSession* session = [NSURLSession sessionWithConfiguration:sessionConf];

NSURL* url = [NSURL URLWithString: [_textUrl stringValue]];

[[session dataTaskWithURL:url completionHandler:handler] resume];

如何更改Connection 的 header ?而且我不想使用另一个 websocket 库,我想在低级别处理 HTTP header 。

可能,除了 NSURLSession 之外,还有其他与网络一起工作的类吗?在NSURLRequest中同样的问题。

最佳答案

要以低级别管理 HTTP header ,最好的方法是使用 CFNetwork 级别。但不要使用 CFHTTPStream 发送/接收数据,因为 CFHTTPStream 仅支持“Connection” header 的两种状态:“keep-alive”和“close”。
参见文件https://opensource.apple.com/source/CFNetwork/CFNetwork-128/HTTP/CFHTTPStream.c
函数“extern void cleanUpRequest()”。

解决方案:
1 通过CFHTTPMessageRefCFHTTPMessageSetHeaderFieldValue创建和自定义请求
2 将请求转换为原始数据
3 发送/接收原始数据使用NSOutputStream和NSInputStream

这是在 CFNetwork 级别发送/接收 HTTP WebSocket 消息的最小示例:

#import "AppDelegate.h"

@implementation AppDelegate

NSInputStream* inputStream;
NSOutputStream* outputStream;

NSMutableData* inputBuffer; // This data receive from server
NSMutableData* outputBuffer; // This data send to server

- (IBAction)btnSend:(id)sender
{
NSURL* url = [NSURL URLWithString: [_textUrl stringValue]];

if( !outputBuffer)
{
outputBuffer = [[NSMutableData alloc] init];
}

///////////////////////////////////////////////////////////////
/////////////// Create GET request uses CFNetwork level
CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), (__bridge CFURLRef)url, kCFHTTPVersion1_1);

// Set Host header
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Host"), (__bridge CFStringRef)(url.port ? [NSString stringWithFormat:@"%@:%@", url.host, url.port] : url.host));
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("User-Agent"), CFSTR("Chrome/36.0.198.5.143"));
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Pragma"), CFSTR("no-cache"));
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Cache-Control"), CFSTR("no-cache"));

// Set special headers for websocket, detail on http://learn.javascript.ru/websockets
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Upgrade"), CFSTR("websocket"));
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Connection"), CFSTR("Upgrade"));
NSString* origin = @"http://from.com";
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)origin);
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Protocol"), CFSTR("SIP"));
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), CFSTR("yuPCDHanXBphfIH83e4JVw=="));
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Version"), CFSTR("13"));
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Extensions"), CFSTR("permessage-deflate; client_max_window_bits, x-webkit-deflate-frame"));

// Convert request to raw data
NSData* rawHttpMessage = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(request));
[outputBuffer appendData:rawHttpMessage];

CFRelease(request);

/////////////////////////////////////////////////////////////////
/////////////// Customize stream for sending/receive data
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)url.host, [url.port intValue],
&readStream, &writeStream);

inputStream = (__bridge_transfer NSInputStream*)readStream;
outputStream = (__bridge_transfer NSOutputStream*)writeStream;
[inputStream setDelegate:self]; // Activate stream event handler
[outputStream setDelegate:self]; // Activate stream event handler
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
[inputStream retain];
[outputStream retain];
}

// Handler of event for NSInputStream and NSOutputStream
// Detail see: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Streams/Articles/NetworkStreams.html
-(void)stream:(NSStream*)stream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode)
{
case NSStreamEventHasSpaceAvailable: // when outputstream can send data
if( stream == outputStream)
{
//NSLog(@"Send data [%lu]", [outputBuffer length]);

[outputStream write:[outputBuffer bytes] maxLength:[outputBuffer length]]; // Send data

// Close output stream when all data sent
[outputStream close];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream release];
outputStream = nil;
[outputBuffer release];
outputBuffer = nil;
}
break;
case NSStreamEventHasBytesAvailable: // when inputstream received data
{
const int bufSize = 2048;

if(!inputBuffer)
{
inputBuffer = [[NSMutableData data] retain];
}

uint8_t buf[bufSize];
long len = 0;
len = [inputStream read:buf maxLength:bufSize]; // get data

if(len)
{
[inputBuffer appendBytes:(const void*)buf length:len];

//NSLog(@"Received data from server [%lu]: %@", [inputBuffer length], inputBuffer); // Show in raw format
NSString* rs = [NSString stringWithUTF8String:[inputBuffer bytes]];
NSLog(@"Received data from server [%lu]:\n%@", [inputBuffer length], rs); // Show in string format
}
else
{
NSLog(@"Received data Error[%li]: %@",(long)[inputStream.streamError code], [inputStream.streamError localizedDescription]);
}

// Close inputStream stream when all data receive
[inputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream release];
inputStream = nil;
[inputBuffer release];
inputBuffer = nil;
}
break;
case NSStreamEventErrorOccurred: // when error of transmited data
if( stream == outputStream)
{
NSError* error = [stream streamError];
NSLog(@"Error sending data [%li]: %@",(long)[error code], [error localizedDescription]);
}
else if( stream == inputStream)
{
NSError* error = [stream streamError];
NSLog(@"Error receive data [%li]: %@",(long)[error code], [error localizedDescription]);
}
break;
case NSStreamEventEndEncountered: // this is not work ;)
if( stream == outputStream)
{
NSLog(@"outputStream End");
}
else if( stream == inputStream)
{
NSLog(@"inputputStream End");
}
break;
}
}

@end

此示例发送 WebSocket 请求并接收 WeSocket 响应:

向服务器发出 WebSocket 请求:

GET / HTTP/1.1
Host: serverwebsocket.com:10080
Upgrade: websocket
Connection: Upgrade
Origin: http://from.com
Sec-WebSocket-Protocol:SIP
Sec-WebSocket-Key: yuPCDHanXBphfIH83e4JVw==
Sec-WebSocket-Version: 13

来自服务器的 WebSocket 响应:

HTTP/1.1 101 Switching Protocols
Content-Length: 0
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: mEgcu0WkPuU6yMRtyUl/C+X8zJE=
Sec-WebSocket-Protocol: sip
Sec-WebSocket-Version: 13

关于ios - NSURLSession 将 header 'Connection' 设置为 'Upgrade' 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25687760/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com