1.接口地址配置
我们打开clash的配置主文件夹,找到config.yaml,查看关于api端口和密码的设置。
以下是一个config.yaml文件示例:
mixed-port: 7890allow-lan: trueexternal-controller: 127.0.0.1:53365secret: 29c0c9ba-1740-42c0-bb8c-dd316c5d1e4aipv6: falselog-level: info
其中external-controller为API的IP和端口配置,如果需要其他机器能够访问这个接口,需要将IP设置为0.0.0.0,secret为API接口密码。
以下是ClashForWindows打开config.yaml文件夹的方法
2.ClashForWindows常用HTTP接口详细介绍
获取所有代理
GET /proxies
获取 Clash 中所有的代理200 代理类型: Direct | Reject | Selector | Shadowsocks | Socks5 | URLTest 类型为 Selector 时有 all 和 now 两个字段,分别代表所含有的代理以及现在选中的代理 类型未 URLTest 时 now 字段为现在最快的代理名字
{"proxies": {"DIRECT": {"type": "Direct"},"GLOBAL": {"all": ["Proxy","auto","🇭🇰"],"now": "Proxy","type": "Selector"},"Proxy": {"all": ["auto","🇭🇰"],"now": "auto","type": "Selector"},"REJECT": {"type": "Reject"},"auto": {"now": "🇭🇰","type": "URLTest"},"🇭🇰": {"type": "Shadowsocks"}}}
获取单个代理的延迟
GET /proxies/:name/delay
获取 Clash 中单个代理的延迟
Path Parameters
Name | Type | Description |
---|---|---|
name | string | 代理名 (大小写敏感) |
Query Parameters
Name | Type | Description |
---|---|---|
timeout | number | 超时时间 (ms) |
url | string | 测试代理的目标网址 |
返回状态码:200 正常返回、400请求格式错误、404代理不存在、408代理请求超时
{"delay": 200}
切换 Selector 中选中的代理
PUT /proxies/:name
当前接口只支持切换 Selector 中的代理
Path Parameters
Name | Type | Description |
---|---|---|
name | string | 代理名称 (大小写敏感) |
Request Body
Name | Type | Description |
---|---|---|
name | string | 要切换的代理名字 |
返回状态码:204 切换成功、400请求错误、404代理不存在
获得当前的基础设置
GET /configs
{"port": 7890,"socket-port": 7891,"redir-port": 0,"allow-lan": true,"mode": "Rule","log-level": "info"}
增量修改配置
PATCH /configs
传入需要修改的配置即可
Request Body
Name | Type | Description |
---|---|---|
port | integer | HTTP 代理端口 |
socks-port | integer | Socks5 代理端口 |
redir-port | string | Redir 代理端口 |
allow-lan | boolean | 是否把代理监听地址放到 0.0.0.0 |
mode | string | 代理模式 ( Global | Rule | Direct ) |
log-level | string | 设置 TTY 日志等级 ( info | warning | error | debug ) |
返回状态码:204 由于可能出现 RESTful API 流量经过代理的问题,而更换端口需要 Graceful Shutdown 所以统一返回 204 No Content
3.自动换IP方法
参考上述常用API接口,我们可通过”GET/proxies获取所有代理”和”PUT /proxies/:name切换 Selector 中选中的代理”两个接口结合,完成自动获取代理节点,随机更换当前代理节点。(为获取活跃且低延迟的节点,可能需要增加一个定时任务,通过”GET /proxies/:name/delay延迟获取”方法更新节点延迟信息。)
以下是一个java版实现Clash切换IP的功能,此处使用了hutool工具类库。需要提前引入相关的maven依赖。
import cn.hutool.core.collection.CollectionUtil; | |
import cn.hutool.core.net.URLEncodeUtil; | |
import cn.hutool.core.util.RandomUtil; | |
import cn.hutool.core.util.StrUtil; | |
import cn.hutool.http.HttpRequest; | |
import cn.hutool.http.HttpResponse; | |
import cn.hutool.http.HttpUtil; | |
import cn.hutool.http.Method; | |
import cn.hutool.json.JSONArray; | |
import cn.hutool.json.JSONObject; | |
import cn.hutool.json.JSONUtil; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
public class ClashUtil { | |
private static final Logger log = LoggerFactory.getLogger(ClashUtil.class); | |
/** | |
* clash配置 | |
* external-controller: 127.0.0.1:61920 | |
* secret: 4a1c185f-607e-4ec6-a984-bab952503d5d | |
*/ | |
public static String clashApiUrl = "http://172.17.0.1:61920"; | |
public static String socks5ProxyHost = "172.17.0.1"; | |
public static int socks5ProxyPort = 7891; | |
public static String secret = "4a1c185f-607e-4ec6-a984-bab952503d5d"; | |
//public static String secret = ""; | |
public static String selectorName = "GLOBAL"; | |
public static String curNode = null; | |
public static final List<String> excludeNodes = Arrays.asList(new String[]{"自动选择","故障转移","实验","免费","国内","漏网","Cloudflare" | |
,"Steam","选择","爱奇","动画","DIRECT","REJECT","OneDrive"}); | |
public static List<String> getAllNode(){ | |
HttpRequest request = HttpUtil.createGet(clashApiUrl+"/proxies"); | |
if(StrUtil.isNotEmpty(secret)){ | |
request.header("Authorization","Bearer "+secret); | |
} | |
String result = request.execute().body(); | |
if(StrUtil.isEmpty(result) || !JSONUtil.isTypeJSONObject(result)){ | |
return null; | |
} | |
JSONObject resultObj = JSONUtil.parseObj(result).getJSONObject("proxies"); | |
JSONArray jsonArray = resultObj.getJSONObject(selectorName).getJSONArray("all"); | |
List<String> validNodeList = new ArrayList<>(); | |
for (int i = 0; i < jsonArray.size(); i++) { | |
String itemNodeName = jsonArray.getStr(i); | |
boolean isExcludeNodes = false; | |
for (String excludeNode : excludeNodes) { | |
if(itemNodeName.contains(excludeNode)){ | |
isExcludeNodes = true; | |
break; | |
} | |
} | |
if(isExcludeNodes){ | |
continue; | |
} | |
boolean use = true; | |
//延迟计算 | |
JSONObject nodeDelay = resultObj.getJSONObject(itemNodeName); | |
//失效节点 | |
if(nodeDelay==null || nodeDelay.getJSONArray("history")==null || nodeDelay.getJSONArray("history").size()==0){ | |
continue; | |
} | |
int maxDelay = 1000; | |
JSONArray delayArray = nodeDelay.getJSONArray("history"); | |
for (int i1 = 0; i1 < delayArray.size(); i1++) { | |
JSONObject itemDelay = delayArray.getJSONObject(i1); | |
Integer itemDelayInt = itemDelay.getInt("delay"); | |
if(itemDelayInt>maxDelay || itemDelayInt==0){ | |
use = false; | |
break; | |
} | |
} | |
if(use){ | |
//System.out.println(itemNodeName); | |
validNodeList.add(itemNodeName); | |
} | |
} | |
return validNodeList; | |
} | |
public static void testAllNode(){ | |
HttpRequest request = HttpUtil.createGet(clashApiUrl+"/proxies"); | |
if(StrUtil.isNotEmpty(secret)){ | |
request.header("Authorization","Bearer "+secret); | |
} | |
String result = request.execute().body(); | |
if(StrUtil.isEmpty(result) || !JSONUtil.isTypeJSONObject(result)){ | |
return ; | |
} | |
JSONObject resultObj = JSONUtil.parseObj(result).getJSONObject("proxies"); | |
JSONArray jsonArray = resultObj.getJSONObject(selectorName).getJSONArray("all"); | |
for (int i = 0; i < jsonArray.size(); i++) { | |
String itemNodeName = jsonArray.getStr(i); | |
boolean isExcludeNodes = false; | |
for (String excludeNode : excludeNodes) { | |
if(itemNodeName.contains(excludeNode)){ | |
isExcludeNodes = true; | |
break; | |
} | |
} | |
if(isExcludeNodes){ | |
continue; | |
} | |
//测速 | |
try { | |
HttpUtil.get(clashApiUrl+"/proxies/"+ URLEncodeUtil.encodeAll(itemNodeName) +"/delay?timeout=5000&url=http%3A%2F%2Fwww.gstatic.com%2Fgenerate_204", 10000); | |
} catch (Exception e) { | |
} | |
} | |
} | |
public static boolean changeRandomNode(){ | |
List<String> allNode = getAllNode(); | |
if(CollectionUtil.isEmpty(allNode) || allNode.size()<10){ | |
log.error("not enough node for change"); | |
return false; | |
} | |
String selectNode = RandomUtil.randomEle(allNode); | |
HttpRequest request = HttpUtil.createRequest(Method.PUT,clashApiUrl+"/proxies/"+ selectorName); | |
request.header("Authorization","Bearer "+secret); | |
JSONObject requestBodyObj = new JSONObject(); | |
requestBodyObj.putOnce("name",selectNode); | |
request.body(requestBodyObj.toString()); | |
HttpResponse response = request.execute(); | |
if(response.getStatus()==204){ | |
curNode = selectNode; | |
log.info("change node success:{}",selectNode); | |
return true; | |
} | |
log.error("change node error,:{}",response.body()); | |
return false; | |
} | |
public static void main(String[] args) { | |
changeRandomNode(); | |
} | |
} |
自动换IP功能可广泛用于自动化注册、网络爬虫等场景。