我试图服务一个视频文件作为响应时,某些请求击中服务器(服务器运行在移动应用程序)。例如:有人上http://mylocalip:8080/video,我想给他发一段视频。
视频文件可以本地存储,也可以外部存储。我开始尝试提供位于SMB服务器上的文件,所以我尝试使用此代码从服务器获取文件并返回它(我知道它正在等待整个文件读取而不是读取和发送块,但应该工作正确吗?):
webServer.addDefaultHandlerForMethod("GET", requestClass: GCDWebServerRequest.self, processBlock: {request in
print("########n########Request: (request)")
let webrequested:GCDWebServerRequest = request;
let urlcita:String = String(webrequested.URL)
print("URL of requests(urlcita)")
if urlcita.rangeOfString("videosmb") != nil{
print("It's a video SMB request")
//Test fake SMB file predefined. Read File using KxSMB
let route:String = "smb://192.168.1.205/ServidorAH/video.avi";
let extensFile:NSString = (route as NSString).pathExtension
let contentype = GCDWebServerGetMimeTypeForExtension(extensFile as String);
print("Content type MIME (contentype)")
//Open SMB file using KxSMB
let authcredentials = KxSMBAuth.smbAuthWorkgroup("", username: "Guest", password: "");
let provider = KxSMBProvider.sharedSmbProvider()!
let archivoes = provider.fetchAtPath(route, auth: authcredentials)
//Switch to manually end the reading when switched to true. In the future will send chunks of data until the end, instead of reading the whole file first.
var interruptor:Bool = false
//Response Stream block
let responseStream: GCDWebServerStreamedResponse = GCDWebServerStreamedResponse(contentType: contentype, asyncStreamBlock: { completionBlock in
if (interruptor == true)
{
print("Test: End of reading")
completionBlock(NSData(), nil);
}
if archivoes!.isKindOfClass(NSError){
//It can not find the file, SMB error, so empty NSDATA to completion block
let errorcito:NSError = archivoes as! NSError
print("Error obteniendo archivo SMB: (errorcito.localizedDescription)");
completionBlock(NSData(), nil);
}else{
print("Archivo SMB adecuado (archivoes)")
let datos:NSData = archivoes!.readDataToEndOfFile()
//Print lenght of data (to check the size of the file)
print("Data lenght (datos.length)")
//Set switch to true, so the next call will send an empty daya completion block
interruptor = true
//Send data chunk (in this case everything)
completionBlock(datos, nil);
}
})
return responseStream
}else{
//Default response
return GCDWebServerDataResponse(HTML:"<html><body><p>Hello World<br></p></body></html>")
}
然而,我不能使它工作。我总是遇到管道破裂的错误,并且访问web服务器的web播放器(从mac和iOS浏览也是如此)无法播放任何内容。我还尝试使用嵌入式iOS播放器来记录响应(KxMovie)。我得到这样的东西:
[DEBUG] Did open connection on socket 19
[DEBUG] Connection received 177 bytes on socket 19
[DEBUG] Connection on socket 19 preflighting request "GET /videosmb" with 177 bytes body
[DEBUG] Connection on socket 19 processing request "GET /videosmb" with 177 bytes body
[DEBUG] Did connect
[DEBUG] Did start background task
[DEBUG] Connection sent 175 bytes on socket 19
...
使用本地播放器(KxMovie)从应用程序内部,这里似乎正在读取文件头,它得到正确的文件大小和视频的尺寸。然而,它不播放,并结束说它到达视频结束(没有播放)。在此之后,WebServer显示一个错误:
...
[ERROR] Error while writing to socket 19: Broken pipe (32)
[DEBUG] Did close connection on socket 19
[VERBOSE] [fe80::cd0:28cd:3a37:b871%en1:8080] fe80::cd0:28cd:3a37:b871%en1:50109 200 "GET /videosmb" (177 | 175)
[DEBUG] Did disconnect
[DEBUG] Did end background task
考虑到这是我第一次处理SMB服务器,我想也许我在SMB部分做错了什么,所以我决定采用简化的方法,只是为了测试。这次我尝试提供一个存储在远程web服务器(不是SMB)上的简单mp4文件。它也没起作用。最后,我尝试在应用程序的主Bundle中提供一个本地文件,同样的情况发生了:什么也没有。下面是代码:
webServer.addDefaultHandlerForMethod("GET", requestClass: GCDWebServerRequest.self, processBlock: {request in
print("########n########Request: (request)")
let webrequested:GCDWebServerRequest = request;
let url:String = String(webrequested.URL)
print("URL of request: (url)")
if url.rangeOfString("video") != nil{
print("It's a video request")
let rutalocalita = (NSBundle.mainBundle()).pathForResource("video", ofType: "avi")
let datos = NSData(contentsOfFile: rutalocalita!)!
print("video size: (datos.length)")
return GCDWebServerDataResponse(data: datos, contentType: "video/avi")
}else{
//Default Response: Simple web
return GCDWebServerDataResponse(HTML:"<html><body><p>Hello World<br></p></body></html>")
}
})
日志如下:
[DEBUG] Did open connection on socket 19
[DEBUG] Connection received 177 bytes on socket 19
[DEBUG] Connection on socket 19 preflighting request "GET /video" with 177 bytes body
[DEBUG] Connection on socket 19 processing request "GET /video" with 177 bytes body
[DEBUG] Did connect
[DEBUG] Did start background task
[myCUSTOMDebug] Read 13584902 b. I'm going to send the response back to the request.
[DEBUG] Connection sent 173 bytes on socket 19
...
这里我在应用程序内部使用的本地播放来跟踪响应,能够读取如下内容:
header='HTTP/1.1 200 OK'
2015-10-17 17:51:41.571 videotvtest[262:14252] http_code=200
2015-10-17 17:51:41.571 videotvtest[262:14252] header='Cache-Control: no-cache'
2015-10-17 17:51:41.571 videotvtest[262:14252] header='Content-Length: 13584902'
2015-10-17 17:51:41.572 videotvtest[262:14252] header='Content-Type: video/avi'
2015-10-17 17:51:41.572 videotvtest[262:14252] header='Connection: Close'
2015-10-17 17:51:41.573 videotvtest[262:14252] header='Server: GCDWebServer'
...
[ERROR] Error while writing to socket 19: Broken pipe (32)
[DEBUG] Did close connection on socket 19
[VERBOSE] [fe80::cd0:28cd:3a37:b871%en1:8080] fe80::cd0:28cd:3a37:b871%en1:50155 200 "GET /video" (177 | 173)
netbios_ns_send_name_query, name query sent for '*'.
[DEBUG] Did disconnect
[DEBUG] Did end background task
我正在玩tvOS和Xcode 7为此,但我想它应该是好的,如果我能够显示一个常规的HTML响应…所以我确信我错过了一些东西,或者也许我错过了一些框架时安装WebServer(我不使用pod)?提前感谢
如果你想提供一个可以在浏览器中使用video标签播放的视频文件,至少在Chrome和Safari上,你需要实现HTTP范围请求。
GCDWebServer自动实现范围支持如果你使用GCDWebServerFileResponse
。如果您使用另一种类型的响应,则需要根据传入GCDWebServerRequest
的byteRange
属性自己实现。您应该从GCDWebServerFileResponse.m
复制粘贴逻辑。