You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何通过指定浏览器VPN连接发起URL请求获取内网JSON

自定义协议触发VPN并请求内网数据的问题解决

问题场景

在iPad应用中需从外网访问内网获取JSON数据,已配置的VPN仅在VMWare浏览器中生效,Safari使用普通网络连接。尝试用awbs://替代https://触发VPN配置,无需打开浏览器直接发起请求,但修改代码后出现unsupported URL错误。

相关代码

func getData() async {

    @State var value: [responsejson]?
    guard let url = URL(string: "https:/...") else {
                print("Invalid URL")
                return
            }
    let request = URLRequest(url: url)

            URLSession.shared.dataTask(with: request) {data, response, error in
                if let data = data {
                    if let decodedResponse = try? JSONDecoder().decode(responsejson.self, from: data) {
                        DispatchQueue.main.async {
                            self.response = decodedResponse.text
                        }
                        return
                    }
                }
                print("Error: \(error?.localizedDescription ?? "Unknown error")")

            }.resume()
}

报错信息

Task <1039D056-FDC4-46EE-9635-373AF8723409>.<1> finished with error [-1002] Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=awbs://(...)

问题原因

URLSession仅支持系统默认的网络协议(如http://、https://),自定义协议awbs://不在其支持范围内,因此直接替换协议会触发unsupported URL错误。另外,自定义协议的设计初衷是唤起第三方应用(如mailto://唤起邮件),而非直接发起网络请求。

解决方案

方案1:让应用直接使用VPN网络通道

检查VPN的应用权限配置,将你的iPad应用添加到VPN的允许列表中。部分VPN支持按应用隔离网络,添加后应用发起的https://请求会自动走VPN通道,无需修改协议。

方案2:自定义URLProtocol处理awbs协议

通过自定义URLProtocol拦截awbs://请求,将其转换为https://的内网请求,同时确保请求走VPN通道。示例代码如下:

class AWBSURLProtocol: URLProtocol {
    override class func canInit(with request: URLRequest) -> Bool {
        return request.url?.scheme == "awbs"
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        return request
    }

    override func startLoading() {
        guard let url = request.url else {
            client?.urlProtocol(self, didFailWithError: NSError(domain: "AWBSProtocol", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效URL"]))
            return
        }
        // 将awbs://转换为https://
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
              var httpsComponents = components.copy() as? URLComponents else {
            client?.urlProtocol(self, didFailWithError: NSError(domain: "AWBSProtocol", code: -2, userInfo: [NSLocalizedDescriptionKey: "转换URL失败"]))
            return
        }
        httpsComponents.scheme = "https"
        guard let httpsURL = httpsComponents.url else {
            client?.urlProtocol(self, didFailWithError: NSError(domain: "AWBSProtocol", code: -3, userInfo: [NSLocalizedDescriptionKey: "生成HTTPS URL失败"]))
            return
        }

        var modifiedRequest = request
        modifiedRequest.url = httpsURL

        // 发起转换后的请求
        let task = URLSession.shared.dataTask(with: modifiedRequest) { [weak self] data, response, error in
            guard let self = self else { return }
            if let error = error {
                self.client?.urlProtocol(self, didFailWithError: error)
                return
            }
            if let response = response {
                self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
            }
            if let data = data {
                self.client?.urlProtocol(self, didLoad: data)
            }
            self.client?.urlProtocolDidFinishLoading(self)
        }
        task.resume()
    }

    override func stopLoading() {
        // 可添加任务取消逻辑
    }
}

// 在应用启动时注册自定义Protocol
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    URLProtocol.registerClass(AWBSURLProtocol.self)
    return true
}

注意:使用前需确保VPN已激活,或在转换请求前先启动VPN。

方案3:先唤起VPN再发起HTTPS请求

如果VPN提供了URL Scheme唤起接口(如vpnprovider://connect),可先调用该Scheme启动VPN,待连接成功后再发起原https://请求:

func startVPNThenFetchData() {
    guard let vpnURL = URL(string: "vpnprovider://connect") else {
        print("无效的VPN唤起URL")
        return
    }
    UIApplication.shared.open(vpnURL) { success in
        if success {
            // 等待VPN连接(等待时间根据实际情况调整)
            DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                self.getData()
            }
        } else {
            print("唤起VPN失败")
        }
    }
}

内容的提问来源于stack exchange,提问作者larud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 03:51:36