# NSURLErrorDomain -1200：iOS App 提示“发生了 SSL 错误”

> NSURLErrorDomain Code=-1200 表示 iOS 或 macOS App 的 TLS 握手失败，常和 App Transport Security（ATS）规则有关。排查和修复方法。

Source: https://ssl.sh/zh/errors/nsurlerrordomain-1200/
Last updated: 2026-11-10

**NSURLErrorDomain Code=-1200 的意思是：iOS 或 macOS 上的 App 无法建立安全连接，TLS 握手失败了。** 苹果的 URL 加载系统会执行 App Transport Security（ATS），所以某些浏览器能打开的服务器，在 App 里照样可能失败。修法几乎都在服务器端，偶尔在 App 的 ATS 设置里。

## 先判断是网站的问题还是你设备的问题

所有用户都失败是服务器的问题，只有部分用户失败多半是网络或设备的问题。用 [SSL 检测](https://ssl.sh/zh/tools/ssl-checker/) 查 App 访问的接口域名或网站：

```bash
curl ssl.sh/example.com
```

服务器不支持 TLS 1.2、套件太弱或证书链不完整，所有用户都会失败。服务器检测通过、只有部分用户失败，就看他们的网络和已安装的描述文件。在 Mac 上，用苹果的 ATS 诊断工具测试 App 实际访问的地址：

```bash
nscurl --ats-diagnostics --verbose https://api.example.com
```

## 原因

5 种原因里，前 3 种出在服务器的协议、证书或证书链上，后两种出在网络拦截和 App 的证书固定。

### 1. 服务器不满足 ATS 要求

ATS 要求 TLS 1.2 及以上和前向保密（ECDHE）套件。只提供 TLS 1.0/1.1 或 RSA 密钥交换的服务器会报 -1200。国内一些老旧的接口服务器、前面挂着老负载均衡的系统经常是这种情况。

### 2. 证书不符合苹果的规则

SHA-1 签名、RSA 密钥小于 2048 位、没有 SAN、有效期过长，都会让 ATS 或苹果的信任评估失败。看失败发生在哪一步，会报 -1200 或 -1202。

### 3. 证书链不完整或私有 CA

缺中间证书、或者私有 CA 的根证书没装，通常报 -1202，但有些握手路径会报 -1200。用 [证书链工具](https://ssl.sh/zh/tools/chain-builder/) 修好证书链。

### 4. 网络拦截

公司代理、需要认证的公共 Wi-Fi、VPN 或过滤类描述文件都可能破坏 TLS。用蜂窝数据测试。

### 5. 证书固定（Pinning）不匹配

App 固定了某张证书或公钥，服务器换了证书，App 自己的固定逻辑就会拒绝连接，常常表现为 -1200 或请求被取消（-999）。

## 在各浏览器/系统上的样子

同一个握手问题，App 日志里是 -1200，Safari 里是“无法建立安全连接”；证书不受信任时则改报 -1202。

| 场景 | 显示内容 |
|---|---|
| iOS / macOS App 日志 | `NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."` |
| 同一服务器在 Safari 里 | [“Safari 无法建立安全连接”](https://ssl.sh/zh/errors/safari-cant-establish-secure-connection/) |
| App 里证书不受信任 | `NSURLErrorDomain Code=-1202` |
| 安卓 App | [Trust anchor for certification path not found](https://ssl.sh/zh/errors/android-trust-anchor-not-found/) 或 `SSLHandshakeException` |

## 站长怎么修

修法以服务器为主：开启 TLS 1.2 以上和 ECDHE 套件，使用公开证书和完整证书链；ATS 例外只作最后手段。

**1. 让服务器达到 ATS 标准。**

```nginx
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_certificate /etc/nginx/ssl/api.example.com.fullchain.pem;
```

接口放在阿里云/腾讯云负载均衡或 API 网关后面的，在控制台把 TLS 安全策略调到最低 TLS 1.2。

**2. 使用公开证书和完整证书链。** 用 `curl ssl.sh/example.com` 检查。

**3. 服务器实在改不了时**，只针对那一个域名在 App 的 Info.plist 里加例外：

```xml
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>legacy.example.com</key>
    <dict>
      <key>NSExceptionRequiresForwardSecrecy</key>
      <false/>
    </dict>
  </dict>
</dict>
```

**4. 提前规划证书固定的轮换**：固定多个公钥，并在服务器换证书之前发布新版 App。
