我终于找到了答案。
Charles 3.11.2完美支持WebSocket。
我使用socketIO,在协商阶段已经看到了发送的http请求,但是我错过了websocket的流量。
一开始,socketIO尝试使用polling,然后切换到使用websockets。
当您访问状态为"Sending request body"的请求时,就可以看到websocket流量,它实际上是wss://请求。
甚至有一个专门用来显示这种流量的选项卡。其余消息将在此处显示。
PS1.确保连接到socket后再在Charles中查看。
PS2.建议使用socketIO,它对于全双工流量(如websocket)是一个重大改进。
2022年6月更新:尽管socket.io-client-swift具有启用SOCKS代理的API,但似乎Starscream v4已经删除了内置的SOCKS代理支持,因此此选项实际上没有任何作用!
因此,看起来我们又回到了手动修补Starscream以启用SOCKS代理的地步。
简而言之,我们已经从Starscream支持SOCKS代理但是socket.io-client-swift没有API来启用它,变成了现在socket.io-client-swift具有启用SOCKS代理的API,但Starscream不再支持该功能。
2019年6月更新:据说socket.io-client-swift v15.1.0现在可以正确支持SOCKS代理。我还没有尝试过,但这意味着不再需要对Starscream进行手动编辑。
已接受的答案似乎无法在iOS设备上使用Socket.IO。
最新版本的Socket.IO-Client-Swift(撰写本文时为15.0.0)在iOS/OS X上使用Starscream进行WebSockets。
好消息是,Starscream支持SOCKS代理,但是:
Socket.IO不公开Starscream websocket,也没有提供任何API来启用SOCKS代理行为。
内置在Starscream中的SOCKS代理使用操作系统的SOCKS代理设置,这些设置很难设置(至少对于iOS而言)。
如果我有时间,我可能会建议一个PR来更彻底地解决这个问题,但考虑到它需要对Starscream和Socket.IO-Client-Swift进行工作,这并不完全简单。
临时解决此问题的最简单方法(这是Charles的使用情况!)是编辑WebSocket.swift文件,并替换此代码:
if enableSOCKSProxy {
let proxyDict = CFNetworkCopySystemProxySettings()
let socksConfig = CFDictionaryCreateMutableCopy(nil, 0, proxyDict!.takeRetainedValue())
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
CFWriteStreamSetProperty(outputStream, propertyKey, socksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, socksConfig)
}
使用这段代码:
let socksConfig = CFDictionaryCreateMutableCopy(nil, 0, CFNetworkCopySystemProxySettings()!.takeRetainedValue()) as! [String: Any]
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
let ip = socksConfig["HTTPSProxy"]
let proxySocksConfig = ["SOCKSProxy": ip, "SOCKSPort": 8889, "SOCKSEnable": true] as CFDictionary // Where 8889 is the SOCKS proxy port in Charles
CFWriteStreamSetProperty(outputStream, propertyKey, proxySocksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, proxySocksConfig)
这将确保默认启用SOCKS代理,并通过Charles路由所有的Websockets流量。
然后,您需要确保在iOS中配置HTTP代理设置(因为相同IP将被用于HTTP和SOCKS),在Charles中启用SOCKS代理,并且端口与上述代码中的端口匹配(默认为8889)。
if enableSOCKSProxy { ... }
),那么您就不需要设置enableSOCKSProxy = true
,它将默认为所有连接启用。 - Jonathan Ellis感谢您非常有帮助的回答Jonathan Ellis!我正在使用Pusher,这个方法很有效!
但是,我发现socksConfig
并不总是包含有效数据,当我从那里提取IP时,它未能正常工作,或者会导致应用程序崩溃。由于我们从那里只获取本地主机IP,因此我只需在WebSocket.swift
中替换以下内容。
if enableSOCKSProxy {
let proxyDict = CFNetworkCopySystemProxySettings()
let socksConfig = CFDictionaryCreateMutableCopy(nil, 0, proxyDict!.takeRetainedValue())
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
CFWriteStreamSetProperty(outputStream, propertyKey, socksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, socksConfig)
}
使用以下内容:
let propertyKey = CFStreamPropertyKey(rawValue: kCFStreamPropertySOCKSProxy)
let proxySocksConfig = ["SOCKSProxy": "127.0.0.1", "SOCKSPort": 8889, "SOCKSEnable": true] as CFDictionary // Where 8889 is the SOCKS proxy port in Charles
CFWriteStreamSetProperty(outputStream, propertyKey, proxySocksConfig)
CFReadStreamSetProperty(inputStream, propertyKey, proxySocksConfig)
按照您的描述,我已经在Charles中启用了socks代理。
再次感谢!
反向代理
强制模拟器使用它。
在Charles中,点击代理 -> 反向代理
,设置一个本地地址作为您的WebSocket服务器的透明代理,然后在您的new WebSocket(<address>)
中使用该地址(在React Native的情况下),然后您就可以在Charles中看到您的WebSocket连接了。使用CharlesProxy连接iOS WebSocket
var rd: InputStream
var wr: OutputStream
let dict: NSDictionary = [
StreamSOCKSProxyConfiguration.hostKey.rawValue : <ip>,
StreamSOCKSProxyConfiguration.portKey.rawValue : <port>
]
rd.setProperty(dict, forKey: Stream.PropertyKey.socksProxyConfigurationKey)
wr.setProperty(dict, forKey: Stream.PropertyKey.socksProxyConfigurationKey)
或者
let proxyDict = CFNetworkCopySystemProxySettings()
let prop = CFDictionaryCreateMutableCopy(nil, 0, proxyDict!.takeRetainedValue())
rd.setProperty(prop, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySOCKSProxy as String as String))
wr.setProperty(prop, forKey: Stream.PropertyKey(rawValue: kCFStreamPropertySOCKSProxy as String as String))
CharlesProxy设置
Proxy -> Proxy Settings... -> Proxies -> Enable SOCKS Proxy
同时,您可以使用websocket-tester检查/审查套接字连接。
请注意,出于安全原因,它应仅在调试模式下使用,并且可能会有其他逻辑(例如检查签名...)来防止拦截流量。