Clash HTTP API接口详解及自动换IP办法

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文件夹的方法



Clash HTTP API接口详解及自动换IP办法
windows打开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


NameTypeDescription
namestring代理名 (大小写敏感)


Query Parameters


NameTypeDescription
timeoutnumber超时时间 (ms)
urlstring测试代理的目标网址


返回状态码:200 正常返回、400请求格式错误、404代理不存在、408代理请求超时



{"delay": 200}

切换 Selector 中选中的代理

PUT /proxies/:name

当前接口只支持切换 Selector 中的代理

Path Parameters


NameTypeDescription
namestring代理名称 (大小写敏感)


Request Body


NameTypeDescription
namestring要切换的代理名字


返回状态码: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


NameTypeDescription
portintegerHTTP 代理端口
socks-portintegerSocks5 代理端口
redir-portstringRedir 代理端口
allow-lanboolean是否把代理监听地址放到 0.0.0.0
modestring代理模式 ( Global | Rule | Direct )
log-levelstring设置 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功能可广泛用于自动化注册、网络爬虫等场景。