ios 通过NWConnection的HTTP请求

jm81lzqq  于 2023-10-21  发布在  iOS
关注(0)|答案(1)|浏览(175)

我有以下设置:

  • 一台运行轻量级服务器(Node.js/Express)的笔记本电脑,假设服务器监听端口3000,并使用JSON响应GET /hello
  • iOS应用

笔记本电脑和iOS设备通过以太网电缆连接到一个本地网络。服务器在网络上使用名称(比如说,“simply.server”)(使用mdns节点包)来自我验证。
iOS应用程序能够在网络框架的帮助下发现此服务器:

// in the beginning of the class declaration
private var browser: NWBrowser?

func discoverServer() {
  let parameters = NWParameters()
  self?.browser = NWBrowser(for: .bonjour(type: "_http._tcp", domain: "local."), using: parameters)
  self?.browser?.stateUpdateHandler = { [weak self] newState in
    switch newState {
    case .failed(let error):
      self?.browser?.cancel()
    default:
      break
    }
  }                           
            
  self?.browser?.browseResultsChangedHandler = { [weak self] results, changes in
    for change in changes {
      switch change {
      case .added(let result):
        switch result.endpoint {
        case .service(let name, _, _, _):
          if name == "simple.server" {
            let connection = NWConnection(to: result.endpoint, using: .tcp)
            connection.stateUpdateHandler = { newState in
              switch newState {
              case .ready:
                if let innerEndpoint = connection.currentPath?.remoteEndpoint,
                  case .hostPort(let host, let port) = innerEndpoint {
                    let content =
                      "GET /hello HTTP/1.1\r\n" +
                      "Host: \(host)\r\n" +
                      "\r\n"
                    let completion = ... just print an error if any
                    connection.receive(minimumIncompleteLength: 1, maximumLength: 10000) { content, _, _, _ in
                      if let content = content {
                        print(String(data: content, encoding: .utf8))
                      }
                    }
                    connection.send(content: content.data(using: .utf8), completion: completion)
                                                    
                                                    
 ... the rest of closing brackets are here
}

这成功地发送了HTTP GET请求(我假设也适用于POST,我还没有测试过),并接收响应。
问题是response是一个原始字符串,像这样:

"HTTP/1.1 200 OK\r\nX-Powered-By: Express\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: 215\r\nETag: W/\"d7-/V8YoIpwjOAIzkBGCymxNZtfrTw\"\r\nDate: Thu, 19 Oct 2023 12:58:08 GMT\r\nConnection: keep-alive\r\nKeep-Alive: timeout=5\r\n\r\n{\"items\":\" 1: \\\"something\\\"\\r\\n 2: \\\"something else\\\"\\r\\n 3: \\\"yet another one\\\"\\r\\n 4: \\\"and so on\\\"\\r\\n 5: \\\"and so forth\\\"\\r\\n 6: \\\"the end\\\"\\r\\n\\n\"}"

为了理解这样的响应,我必须手动解析它(例如,通过换行符拆分,解析出响应代码,头,主体等),这有点麻烦。
所以我的问题是我怎么才能让它更好

  • 有没有一种方法可以很好地将其解析为HTTPURLResponse?
  • 也许一开始就有更好的方法来完成请求
  • 也许我不应该通过NWConnection这样做,而是在发现服务后使用URLSession?

提前感谢您的任何建议。

1tu0hz3e

1tu0hz3e1#

更新:

最后我成功地发送了一个HTTP请求。
正如@Paulw11在评论中提到的,可以用我们已经从connection.currentPath?.remoteEndpoint解析的主机和端口构建一个URL。
有几件事要注意:

  1. host是一个ipv6地址(在我的情况下;我试图在服务器端进行更改以强制IPv4,但它不起作用;我还没有深入研究),所以它应该包含在[]中,我完全错过了。我们还可以打开host来查看它是ipv4还是ipv6,并相应地构建url。
    1.由于某种原因,URLSession.shared.dataTask调用完成从来没有调用完成。但是URLSession.shared.data(for:),运行得很好(同样,甚至还没有尝试弄清楚)。
    1.如果plist中禁止任意加载,请求将失败。这还有待我去解决。
    下面是工作代码:
let urlString = "http://[\(host)]:\(port)/printers"
if let url = URL(string: urlString) {
  Task {
    let request = URLRequest(url: url)
    let result = try? await URLSession.shared.data(for: request)
    print(result)
  }
}

相关问题