- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
环境: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 通过CFHTTPMessageRef
和CFHTTPMessageSetHeaderFieldValue
创建和自定义请求
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/
我编写了一个提供一些数据的 REST 服务。它受密码保护。 我正在尝试编写一个后台进程来获取数据并将其填充到我在应用程序中拥有的 sqlLite 数据库中。 我最初是在没有身份验证的情况下使用的: -
我想要一个 API key 并验证用户身份。我在控制台中看到消息“ session URL 任务成功:HTTP 200”。不幸的是,我总是收到页面“{”消息“:”的消息。此请求“}”的授权已被拒绝。我
我为 NSURLSession 创建了类别,然后我遇到了一个问题。在 iOS 7 中,[[NSURLSession sharedSession] isKindOfClass:[NSURLSession
如何从 NSHTTPCookieStorage.sharedHTTPCookieStorage 中删除所有 cookie?我知道删除单个指定 cookie 的唯一方法,但是,这些 cookie 是由
我正在尝试在应用程序进入后台(例如从主页按钮按下)的情况下正确处理进程内 NSURLSessionTasks。我目前正在采用将进程中的任务复制到后台队列的方法(请参见下面的代码)。然而,我发现后台任务
我是 objective-c 中的新手,使用 iOS 9 Xcode 7.2 并收到此警告“'initWithRequest:delegate:'已弃用:在 iOS 9.0 中首次弃用 - 使用 NS
当我导入 Gmail API 的 GTL.xcodeproj 并运行它时出现上述错误。我正在使用 Xcode 7.1 beta 并且在 Gmail API 二进制文件的头文件中出现了很多错误我们不推荐
我在我的 iOS 应用程序中使用 Alamofire 进行网络连接。我需要在 iOS 7+ 中运行这个应用程序。我要在状态栏中指示网络事件 ,所以我创建了这个结构: struct ActivityMa
我需要从服务器下载视频并保存视频以供稍后观看。 所以我需要下载视频并将其使用自定义名称保存在应用程序的文件系统中,到目前为止我可以下载数据(我猜)但无法存储它。 不,我不想使用额外的扩展框架或其他什么
在一个小型 iOS 应用程序中,我需要从服务器检索一些 JSON(类似于 DNS 请求),并使用此响应来发起进一步的连接。为此,我有一个使用 NSURLSession 处理 JSON 请求的对象。该对
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve th
当我尝试在网络离线(飞行模式)时启动基本的 NSURLSession 传输时,使用 NSURLSessionConfiguration defaultSessionConfiguration 和 ep
我曾经用 NSURLConnection 做我想做的事. 我会创建一个新的自定义 NSOperation对象 设置我的 NSMutalbeRequest当准备好触发operation女巫会排队操作..
我创建了一个下载任务。我已经使用cancelByProducingResumeData在应用程序中取消了任务,并将其保存到磁盘。当用户重新启动应用程序并单击“恢复”按钮时,我再次通过self.down
即使在使 NSURLSession 无效后,使用 Instruments 运行配置文件,一些名为 TubeManager、HTTPConnectionCache 和 HTTPConnectionCac
我有一段普通的代码,我几乎在我的代码中到处使用: let configuration = URLSessionConfiguration.default let session = URLSessio
我希望有人能够帮助我理解在我的 WatchOS 2 应用程序中尝试实现 NSURLSession 时遇到的问题。 无论出于何种原因,我收到错误; Error Domain=NSCocoaErrorDo
我正在尝试使用 NSURLSession 从 URL 获取 ID,但是 let task = NSURLSession.... 和 task.resume 之间的代码 永远不会执行(我在里面放置了一个
我正在尝试使用 NSURLSession 发出 HTTPRequest。当我设置完整的 url 时,请求返回正确的数据,但是当使用参数时 (NSJSONSerialization.dataWithJS
我是这方面的新手,但过去常常在这里搜索特定的东西,并且由于我找不到特定的答案,也许这里有人可以提供帮助。 我基本上是在学习和构建一个应用程序。 目前我已经构建登录、注册 View Controller
我是一名优秀的程序员,十分优秀!