# 发起请求

网络解锁器作为HTTP代理运行，并对流量执行中间人（MITM）操作。这使其能够拦截和修改请求，从而绕过反爬保护。

由于MITM机制和所需的SSL处理，不建议在浏览器或Playwright等工具中使用该解锁器。

基于工具特性，我们目前仅支持**GET**请求。

**請求範例：**

{% tabs %}
{% tab title="cURL" %}
{% code overflow="wrap" %}

```
curl -k -v -x http://unblocker.iproyal.com:12323 --proxy-user username:password -L https://ipv4.icanhazip.com
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}

```php
<?php

declare(strict_types=1);

$url = 'https://ipv4.icanhazip.com';
$proxy = 'http://unblocker.iproyal.com:12323';
$proxyAuth = 'username:password';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROXY, $proxy);
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyAuth);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = 'https://ipv4.icanhazip.com'
proxy = 'unblocker.iproyal.com:12323'
proxy_auth = 'username:password'
proxies = {
   'http': f'http://{proxy_auth}@{proxy}',
   'https': f'http://{proxy_auth}@{proxy}'
}

response = requests.get(
   url,
   proxies=proxies,
   verify=False,
   allow_redirects=True,
   timeout=30,
)
print(response.text)
```

{% endtab %}

{% tab title="Node.js" %}

```
const { fetch, ProxyAgent } = require('undici');

const url = 'https://ipv4.icanhazip.com';
const client = new ProxyAgent(
  'http://username:password@unblocker.iproyal.com:12323'
);

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

(async () => {
  try {
    const response = await fetch(url, {
      redirect: 'follow',
      dispatcher: client,
      headers: {
        'user-agent': 'undici-proxy-test'
      }
    });
    const text = await response.text();
    if (!response.ok) {
      console.error(`HTTP ${response.status} ${response.statusText}`);
    }
    console.log(text.trim());
  } catch (error) {
    console.error('Fetch failed:', error);
  }
})();
```

{% endtab %}

{% tab title="Java" %}

```java
import javax.net.ssl.*;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Main {
    private static final String PROXY_HOST = "unblocker.iproyal.com";
    private static final int    PROXY_PORT = 12323;
    private static final String USERNAME   = "username";
    private static final String PASSWORD   = "password";

    private static final String TARGET_HOST = "ipv4.icanhazip.com";
    private static final int    TARGET_PORT = 443;

    private static final boolean INSECURE_TRUST_ALL = true;

    public static void main(String[] args) {
        try {
            System.out.println(fetchIpThroughProxy());
        } catch (Exception e) {
            System.err.println("ERROR: " + e.getClass().getSimpleName() + ": " + e.getMessage());
        }
    }

    private static String fetchIpThroughProxy() throws Exception {
        final String basic = Base64.getEncoder()
                .encodeToString((USERNAME + ":" + PASSWORD).getBytes(StandardCharsets.ISO_8859_1));

        try (Socket proxy = new Socket()) {
            proxy.connect(new InetSocketAddress(PROXY_HOST, PROXY_PORT), 15_000);
            proxy.setSoTimeout(15_000);

            try (var out = new BufferedWriter(new OutputStreamWriter(proxy.getOutputStream(), StandardCharsets.ISO_8859_1));
                 var in  = new BufferedInputStream(proxy.getInputStream())) {

                out.write("CONNECT " + TARGET_HOST + ":" + TARGET_PORT + " HTTP/1.1\r\n");
                out.write("Host: " + TARGET_HOST + ":" + TARGET_PORT + "\r\n");
                out.write("Proxy-Authorization: Basic " + basic + "\r\n");
                out.write("Proxy-Connection: Keep-Alive\r\n\r\n");
                out.flush();

                final String status = readLine(in);
                if (status == null || !status.startsWith("HTTP/1.1 200")) {
                    throw new IOException("CONNECT failed: " + status);
                }
                drainHeaders(in);

                SSLSocket ssl = (SSLSocket) sslFactory().createSocket(proxy, TARGET_HOST, TARGET_PORT, true);
                SSLParameters params = ssl.getSSLParameters();
                params.setServerNames(java.util.List.of(new SNIHostName(TARGET_HOST)));
                ssl.setSSLParameters(params);
                ssl.startHandshake();

                try (var httpsOut = new BufferedWriter(new OutputStreamWriter(ssl.getOutputStream(), StandardCharsets.ISO_8859_1));
                     var httpsIn  = new BufferedInputStream(ssl.getInputStream())) {

                    httpsOut.write("GET / HTTP/1.1\r\n");
                    httpsOut.write("Host: " + TARGET_HOST + "\r\n");
                    httpsOut.write("User-Agent: JavaRawProxy\r\n");
                    httpsOut.write("Connection: close\r\n\r\n");
                    httpsOut.flush();

                    drainHeaders(httpsIn);
                    return readBody(httpsIn).trim();
                }
            }
        }
    }

    private static SSLSocketFactory sslFactory() throws Exception {
        if (!INSECURE_TRUST_ALL) return (SSLSocketFactory) SSLSocketFactory.getDefault();
        TrustManager[] trustAll = new TrustManager[]{ new X509TrustManager() {
            public void checkClientTrusted(java.security.cert.X509Certificate[] c, String a) {}
            public void checkServerTrusted(java.security.cert.X509Certificate[] c, String a) {}
            public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[0]; }
        }};
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(null, trustAll, new java.security.SecureRandom());
        return ctx.getSocketFactory();
    }

    private static void drainHeaders(InputStream in) throws IOException {
        String line;
        while ((line = readLine(in)) != null && !line.isEmpty()) {}
    }

    private static String readBody(InputStream in) throws IOException {
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        byte[] tmp = new byte[4096];
        int n;
        while ((n = in.read(tmp)) != -1) buf.write(tmp, 0, n);
        return buf.toString(StandardCharsets.ISO_8859_1);
    }

    private static String readLine(InputStream in) throws IOException {
        StringBuilder sb = new StringBuilder();
        int prev = -1, cur;
        while ((cur = in.read()) != -1) {
            if (prev == '\r' && cur == '\n') { sb.setLength(sb.length() - 1); break; }
            sb.append((char) cur); prev = cur;
        }
        return (sb.length() == 0 && cur == -1) ? null : sb.toString();
    }
}
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
    "crypto/tls"
    "encoding/base64"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "time"
)

func main() {
    proxyUser := "username"
    proxyPass := "password"
    proxyStr := "http://unblocker.iproyal.com:12323"

    target := "https://ipv4.icanhazip.com"

    proxyURL, err := url.Parse(proxyStr)
    if err != nil {
        panic(err)
    }
    proxyURL.User = url.UserPassword(proxyUser, proxyPass)

    basic := "Basic " + base64.StdEncoding.EncodeToString([]byte(proxyUser+":"+proxyPass))

    tr := &http.Transport{
        Proxy: http.ProxyURL(proxyURL),

        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},

        ProxyConnectHeader: http.Header{
            "Proxy-Authorization": []string{basic},
        },
    }

    client := &http.Client{
        Transport: tr,
        Timeout:   30 * time.Second,
    }

    resp, err := client.Get(target)
    if err != nil {
        fmt.Println("Request error:", err)
        return
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Printf("HTTP %d\n%s\n", resp.StatusCode, string(body))
}
```

{% endtab %}

{% tab title="C#" %}

```csharp
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Text;

class Program
{
    static async Task Main()
    {
        var url = new Uri("https://ipv4.icanhazip.com");
        var proxy = new Uri("http://unblocker.iproyal.com:12323");
        const string proxyUser = "username";
        const string proxyPass = "password";

        using var client = CreateHttpClient(proxy, proxyUser, proxyPass);
        var ip = (await client.GetStringAsync(url)).Trim();
        Console.WriteLine(ip);
    }

    private static HttpClient CreateHttpClient(Uri proxyUri, string user, string pass)
    {
        var handler = new SocketsHttpHandler
        {
            AllowAutoRedirect = true,
            AutomaticDecompression = DecompressionMethods.All,
            SslOptions = new SslClientAuthenticationOptions
            {
                RemoteCertificateValidationCallback = static (_, _, _, _) => true
            },
            ConnectCallback = async (ctx, ct) =>
            {
                var tcp = new TcpClient();
                await tcp.ConnectAsync(proxyUri.Host, proxyUri.Port);
                var stream = tcp.GetStream();

                var auth = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{pass}"));
                string host = ctx.DnsEndPoint.Host;
                int port = ctx.DnsEndPoint.Port;

                var request =
                    $"CONNECT {host}:{port} HTTP/1.1\r\n" +
                    $"Host: {host}:{port}\r\n" +
                    $"Proxy-Authorization: Basic {auth}\r\n" +
                    "\r\n";

                var bytes = Encoding.ASCII.GetBytes(request);
                await stream.WriteAsync(bytes, 0, bytes.Length, ct);
                await stream.FlushAsync(ct);

                using var reader = new StreamReader(stream, Encoding.ASCII, detectEncodingFromByteOrderMarks: false, bufferSize: 4096, leaveOpen: true);
                var status = await reader.ReadLineAsync();
                if (status is null || !status.Contains(" 200 "))
                    throw new IOException($"Proxy CONNECT failed: {status}");
                
                while (!string.IsNullOrEmpty(await reader.ReadLineAsync())) { }
                return stream;
            }
        };

        var client = new HttpClient(handler)
        {
            Timeout = TimeSpan.FromSeconds(30)
        };
        client.DefaultRequestVersion = HttpVersion.Version11;
        return client;
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
使用网络解锁器时，**必须禁用 HTTPS 证书验证。**
{% endhint %}

**响应代码**

错误代码（通常为HTTP状态码）表示在访问网站时遇到的问题。

常见错误代码包括404（未找到）、403（禁止访问）、502（错误网关）和503（服务不可用）。这些代码有助于确定问题是出在客户端（4xx）、服务器端（5xx）还是重定向（3xx）。

| **响应代码** | **说明**                      |
| -------- | --------------------------- |
| 200      | 请求成功。                       |
| 301/302  | 页面已重定向。                     |
| 403      | 请求被拦截。                      |
| 404      | URL不存在。                     |
| 429      | 达到速率限制。我们目前允许同时最多有200个活跃连接。 |
| 500      | 目标服务器出现问题。                  |
| 502      | 网关或代理服务器未能获取有效响应。           |
| 503      | 服务器过载或停机。                   |
| 504      | 服务器响应超时。                    |
