调用webservice通过HTTP【实验】

前言

本文尝试使用HTTP请求实现调用webservice服务,需求效果参考SOAPUI。

调用WebService方法有多种:

1. 使用Visual Studio的”添加服务引用”功能,在代码中声明服务对象后,即可调用。

优点
方便快捷,节约时间
缺点:
前提条件是开发环境需要能够访问到服务地址,否则无法添加服务引用。
不适用频繁更新的webservice,每次调用的webservice的WSDL文件更新后,必须重新生成覆盖更新旧的代理类。不够便捷及时。

参考:

添加 Web 引用
访问 Web 服务

2. 使用WSDL.exe工具生成代理类,将生成的类添加到项目中,在代码中创建类的实例对象后,即可调用。

优点
方便快捷,只需要WSDL文件就能生成代理
缺点:
不适用频繁更新的webservice,每次调用的webservice的WSDL文件更新后,必须重新生成覆盖更新旧的代理类。不够便捷及时。

生成代理类
1
2
C:\Users\user>cd C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools
C:\Users\user>wsdl.exe /l:cs /n:testnamespace /out: D:testproxy.cs https://www.crcind.com/csp/samples/SOAP.Demo.CLS?WSDL=1

参考:

Web 服务描述语言工具 (Wsdl.exe)
.net wsdl.exe 生成java开发的webservice客户端类的时候报错,无法从命名空间获取绑定
C# 利用VS自带的WSDL工具生成WebService服务类

3. 使用HTTP请求实现调用webservice服务

思路

参考:

C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解 - 懒得安分 - 博客园
WebService 之 WSDL文件 讲解 - 梦想的追求 - CSDN博客
WebAPI 和 webservice的区别 - CYSONG168的专栏 - CSDN博客
【WCF】什么是WCF - 白靖 - CSDN博客
mvc接口、webapi、webservice 对比 - 思明 - 博客园
使用 System.Net 和 SOAP 动态调用 Web 服务
WebService中的WSDL详细解析_孤独地搬砖的博客-CSDN博客_wsdl是什么意思
WSDL Tutorial: Web Services Description Language with Example
Web Service Definition Language (WSDL)
Web Services Description Language (WSDL) Version 2.0 Part 1: Core Language

Client发送SOAP请求并接收响应

SOAPHelper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Xml;

namespace Ryadel.Web.SOAP
{
/// <summary>
/// Helper class to send custom SOAP requests.
/// </summary>
public static class SOAPHelper
{
/// <summary>
/// Sends a custom sync SOAP request to given URL and receive a request
/// </summary>
/// <param name="url">The WebService endpoint URL</param>
/// <param name="action">The WebService action name</param>
/// <param name="parameters">A dictionary containing the parameters in a key-value fashion</param>
/// <param name="soapAction">The SOAPAction value, as specified in the Web Service's WSDL (or NULL to use the url parameter)</param>
/// <param name="useSOAP12">Set this to TRUE to use the SOAP v1.2 protocol, FALSE to use the SOAP v1.1 (default)</param>
/// <returns>A string containing the raw Web Service response</returns>
public static string SendSOAPRequest(string url, string action, Dictionary<string, string> parameters, string soapAction = null, bool useSOAP12 = false)
{
// Create the SOAP envelope
XmlDocument soapEnvelopeXml = new XmlDocument();
var xmlStr = (useSOAP12)
? @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap12:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
xmlns:soap12=""http://www.w3.org/2003/05/soap-envelope"">
<soap12:Body>
<{0} xmlns=""{1}"">{2}</{0}>
</soap12:Body>
</soap12:Envelope>"
: @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<soap:Body>
<{0} xmlns=""{1}"">{2}</{0}>
</soap:Body>
</soap:Envelope>";
string parms = string.Join(string.Empty, parameters.Select(kv => String.Format("<{0}>{1}</{0}>", kv.Key, kv.Value)).ToArray());
var s = String.Format(xmlStr, action, new Uri(url).GetLeftPart(UriPartial.Authority) + "/", parms);
soapEnvelopeXml.LoadXml(s);

// Create the web request
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", soapAction ?? url);
webRequest.ContentType = (useSOAP12) ? "application/soap+xml;charset=\"utf-8\"" : "text/xml;charset=\"utf-8\"";
webRequest.Accept = (useSOAP12) ? "application/soap+xml" : "text/xml";
webRequest.Method = "POST";

// Insert SOAP envelope
using (Stream stream = webRequest.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}

// Send request and retrieve result
string result;
using (WebResponse response = webRequest.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
result = rd.ReadToEnd();
}
}
return result;
}
}
}

参考引用:

Client to send SOAP request and receive response
How to perform a SOAP Web Service Request in ASP.NET C# without using WSDL, proxy classes or SoapClient

什么是Key Lookup?

Key Lookups 可能会导致性能问题
性能调整查询时最容易修复的事情之一是 Key Lookups 或 RID Lookups。当查询优化器对特定表执行index seek并且该索引没有满足结果集所需的所有列时,就会出现key lookup运算符。 SQL Server 被迫使用主键返回聚集索引并检索满足请求所需的剩余列。 RID lookup是相同的操作,但在没有聚集索引的表(也称为堆)上执行。它使用row id 而不是主键来进行查找。
如您所见,这些可能非常昂贵,并且可能导致 I/O 和 CPU 的性能大幅下降。 想象一个每分钟运行数千次的查询,其中包括一个或多个键查找。 这可能会导致由这些额外读取产生的巨大开销,它会影响整体引擎性能。

让我们看一个例子。

demo.sql
1
2
3
4
SELECT [SalesOrderID],[CarrierTrackingNumber],[OrderQty],[ProductID],
[UnitPrice],[ModifiedDate]
FROM [AdventureWorks2014].[Sales].[SalesOrderDetail]
Where [ModifiedDate]> '2014/01/01' and [ProductID]=772

键查找运算符的成本是查询的 99%。 您可以看到它对 IX_SalesOrderDetail_ProductID 执行了索引查找,这非常有效,但是该索引没有满足查询所需的所有列。 然后优化器使用聚集索引 PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID 检索它需要的其他列。 您可以通过将鼠标悬停在查询计划窗口中的键查找上来查看它得到了什么。

Key 和 RID look ups 的好处是它们非常容易修复。 通过对非聚集索引 IX_SalesOrderDetail_ProductID 稍作修改,我们可以将查询计划从index seek和key lookup更改为非常小的索引查找。 我们所要做的就是重新创建该索引并将输出列表字段添加为该索引上的包含列。

demo.sql
1
2
3
4
5
CREATE NONCLUSTERED INDEX [IX_SalesOrderDetail_ProductID] 
ON [Sales].[SalesOrderDetail]([ProductID] ASC)
INCLUDE ([CarrierTrackingNumber],[UnitPrice], [ModifiedDate], [OrderQty])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = ON, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]

正如您所看到的,我们现在只有一个 Index Seek 和一个更有效的计划。

参考引用:

What’s a Key Lookup?
Eliminating bookmark (key/rid) lookups

CSS选择器

Redis常用命令

Redis 常用操作命令,非常详细!

管理命令

命令 操作 备注
redis-server [--port 6379] 启动Redis
redis-server [xx/xx/redis.conf] 通过配置文件来启动Redis
redis-cli.exe -h 127.0.0.1 -p 6379 -a test 连接本地6379端口的redis服务,使用密码test
redis-cli shutdown 停止Redis

key操作命令

命令 操作 备注
keys * 获取所有键 *表示通配符,表示任意字符,会遍历所有键显示所有的键列表,时间复杂度O(n),在生产环境不建议使用。
dbsize 获取键总数 获取键总数时不会遍历所有的键,直接获取内部变量,时间复杂度O(1)。
exists akey bkey 查询键是否存在 可查询多个,返回存在的个数。
del akey bkey 删除键 可以删除多个,返回删除成功的个数。
move akey 2 移动键 把akey移到2号数据库
select 2 选择查询库
ttl akey 查询key的生命周期(秒)
expire akey 60 设置过期时间 60s
persist akey 设置永不过期
rename akey akey123 更改键名称

字符串操作命令

命令 操作 备注
set akey 测试 存放键值
get akey 获取键值
incr bkey 值递增/递减 如果字符串中的值是数字类型的,可以使用incr命令每次递增,不是数字类型则报错
mset akey 测试 bkey 66 批量存放键值
mget akey bkey 批量获取键值
strlen akey 获取值长度
append akey hi 追加内容
getrange akey 0 2 获取部分字符 获取索引0到4的字符串

集合操作命令

集合

有序集合

列表操作命令

散列操作命令

Git初识【一】

常用命令

git仓库命令

命令 操作 备注
git remote -v 查看远程仓库
git pull origin master 直接拉取并合并最新代码 git pull origin dev :拉取远端origin/dev分支并合并到当前分支
git fetch origin master:master1 获取最新代码到本地临时分支 在本地建立master1分支,并下载远端的origin/master分支到master1分支中
git diff master1 查看版本差异 查看本地master1分支与当前分支的版本差异
git merge master1 合并最新分支到本地分支 合并本地分支master1到当前分支
git branch -D master1 删除本地临时分支 删除本地分支master1
git fetch origin master 获取最新代码到本地(本地当前分支为[branch],获取的远端的分支为[origin/branch]) 获取远端的origin/master分支
git log -p master..origin/master 查看版本差异 查看本地master与远端origin/master的版本差异
git merge origin/master 合并最新代码到本地分支 合并远端分支origin/master到当前分支

git配置命令

命令 操作 备注

摘录

创建仓库命令

命令 操作 备注
git init 初始化仓库
git clone 拷贝一份远程仓库,也就是下载一个项目。

提交与修改

命令 操作 备注
git add 添加文件到暂存区
git status 查看仓库当前的状态,显示有变更的文件。
git diff 比较文件的不同,即暂存区和工作区的差异。
git commit 提交暂存区到本地仓库。
git reset 回退版本。
git rm 将文件从暂存区和工作区中删除。
git mv 移动或重命名工作区文件。

提交日志

命令 操作 备注
git log 查看历史提交记录
git blame <file> 以列表形式查看指定文件的历史修改记录

远程操作

命令 操作 备注
git remote 远程仓库操作
git fetch 从远程获取代码库
git pull 下载远程代码并合并
git push 上传远程代码并合并

分支操作

|:–|:–|:–|
|git branch|列出现有的分支|-r导致远程跟踪分支被列出;-a显示本地和远程分支|
|git branch (branchname)|创建分支命令||
|git checkout (branchname)|切换分支命令||
|git checkout -b (branchname)|创建新分支并立即切换到该分支下||
|git branch -d (branchname)|删除分支||
|git merge|合并分支||

Git命令-管理

管理

如果你正在管理一个 Git 仓库,或者需要通过一个复杂的方法来修复某些东西,Git 提供了一些管理命令来帮助你。

git gc

git gc 命令在你的仓库中执行 “garbage collection”,删除数据库中不需要的文件和将其他文件打包成一种更有效的格式。

此命令一般在背后为你工作,虽然你可以手动执行它-如果你想的话。 我们在维护 一节中研究此命令的几个示例。

git fsck

git fsck 命令用来检查内部数据库的问题或者不一致性。

我们只在 数据恢复 这一节中快速使用了一次此命令来搜索所有的悬空对象(dangling object)。

git reflog

git reflog 命令分析你所有分支的头指针的日志来查找出你在重写历史上可能丢失的提交。

我们主要在 引用日志 一节中提到了此命令,并在展示了一般用法,及如何使用 git log -g 来通过 git log 的输出来查看同样的信息。

我们同样在 数据恢复 一节中研究了一个恢复丢失的分支的实例。

git filter-branch

git filter-branch 命令用来根据某些规则来重写大量的提交记录,例如从任何地方删除文件,或者通过过滤一个仓库中的一个单独的子目录以提取出一个项目。

从每一个提交中移除一个文件 一节中,我们解释了此命令,并探究了其他几个选项,例如 –commit-filter,–subdirectory-filter 及 –tree-filter 。

在 Git-p4 和 TFS 的章节中我们使用它来修复已经导入的外部仓库。

详情

git add

  • 添加当前目录下的所有文件到暂存区:git add .

git rm

  • 用法:git rm <filename>;

  • 从暂存区和工作区中删除 demo目录下的test.txt 文件:git rm demo/test.txt

  • 从暂存区和工作区中 强制删除 test.txt 文件:git rm -f test.txt

  • 把文件从暂存区域移除,但仍然保留在当前工作目录中【从跟踪清单中删除 】:git rm --cached test.txt

使用WorkerServices和.NETCore3.1构建Windows服务

笔记

Adding the Quartz.NET hosted service
You need to do two things to register the Quartz.NET hosted service:

  • Register the Quartz.NET required services with the DI container
  • Register the hosted service

根据Quartz文档Microsoft DI Integration 中的描述,在微软的集成中,使用services.AddQuartzHostedService 将服务注册到 hosted service中 。根据源码可以看到是调用了services.AddSingleton方法,注册了一个单例生命周期的服务。

WorkerServices+Quartz+Windows服务 是否可实现?

  • 思路
    一开始以为services.AddQuartzHostedService 就已经是创建了一个服务,但是发现总是不对,问题在于没有添加 Host Service服务。而且AddQuartzHostedService 只是注册了一个单例生命周期的服务,并没有针对Windows服务做进一步的实现。没有实现OnStart 和OnStop 方法。所以一致报错。

    在后面添加上services.AddHostedService<Worker>(); 后,程序可以正常运行,本质上Quartz还是需要依托于一个正常运行的HostService 。而一个正常的Windows服务程序则必须是一个可以长时间运行的 HostService 。需要从BackgroundService派生并覆盖实现必要的部份方法

参考:

为将作为服务应用程序的一部分而存在的服务提供基类。 在创建新的服务类时,必须从 ServiceBase 类 派生。
在服务应用程序中定义服务类时从ServiceBase派生。任何有用的服务都会覆盖OnStart和OnStop方法。对于附加功能,您可以使用特定行为覆盖OnPause和OnContinue,以响应服务状态的变化。

DemoFile:

program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using Quartz;
using WorkerServiceDemoNet6;

IHost host = Host.CreateDefaultBuilder(args)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseWindowsService(option =>
{
option.ServiceName = "NET6.0 Test Windows Service";
})
.ConfigureAppConfiguration((hostingContext, configuration) =>
{
configuration.Sources.Clear();

IHostEnvironment env = hostingContext.HostingEnvironment;

Console.WriteLine("ENVIRONMENT: " + env == null ? "" : env.EnvironmentName ?? "");

configuration
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile(@"appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
})
.ConfigureServices(services =>
{
services.AddQuartz(q =>
{
q.SchedulerId = "Scheduler-Core";

q.UseInMemoryStore();
q.UseDefaultThreadPool(tp =>
{
tp.MaxConcurrency = 10;
});
//Use a Scoped container to create jobs. I'll touch on this later
q.UseMicrosoftDependencyInjectionJobFactory();

//q.AddJobAndTrigger<TestJob>(hostContext.Configuration);

// Create a "key" for the job
var jobKey = new JobKey("TestJob");
// Register the job with the DI container
q.AddJob<TestJob>(opts => opts.WithIdentity(jobKey));
// Create a trigger for the job
q.AddTrigger(opts => opts
.ForJob(jobKey) // link to the HelloWorldJob
.WithIdentity("HelloWorldJob-trigger") // give the trigger a unique name
.WithCronSchedule("0/5 * * * * ?")); // run every 5 seconds

});

//Add the Quartz.NET hosted service
services.AddQuartzHostedService(
q =>
{
q.WaitForJobsToComplete = true;
q.AwaitApplicationStarted = true;
});
})
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
})
.Build();

await host.RunAsync();

转载:
Create a Windows Service using BackgroundService
Building a Windows service with Worker Services and .NET Core 3.1, part 1: Introduction

Using Quartz.NET with ASP.NET Core and worker services
.NET Core Workers as Windows Services

参考:

AddTransient, AddScoped and AddSingleton Services Differences

ASP.NET Core Service Lifetimes (Infographic)

v2ray部署Ubuntu18.0

部署v2ray

按照fhs-install-v2ray文档,一步步执行。

安装和更新 V2Ray

1
2
3
4
# 安装可执行文件和 .dat 数据文件
cd ~
sudo wget https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh
sudo bash install-release.sh

安装最新发行的 geoip.dat 和 geosite.dat

1
2
3
4
# 只更新 .dat 数据文件
cd ~
sudo wget https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-dat-release.sh)
sudo bash install-dat-release.sh

移除 V2Ray

1
2
3
cd ~
sudo wget https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh
sudo bash install-release.sh --remove

安装完后启用服务

1
2
systemctl enable v2ray
systemctl start v2ray

v2ray帮助命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#编辑配置文件
sudo vim /usr/local/etc/v2ray/config.json

#测试配置文件正确性
/usr/local/bin/v2ray/v2ray --test --config /etc/v2ray/config.json

# 查看运行状态
sudo systemctl status v2ray
# 查看端口占用
sudo netstat -apn | grep v2ray
# 查看程序日志
sudo journalctl -b -u v2ray
# 查看v2ray日志文件
sudo vim /var/log/v2ray/access.log
# 查看程序日志文件底部 10 行内容。
sudo tail /var/log/v2ray/error.log
# 启动
sudo systemctl start v2ray
# 停止
sudo systemctl stop v2ray
# 重启
sudo systemctl restart v2ray


## 查看防火墙状态:(active (running) 即是开启状态)
sudo systemctl status firewalld

## 查看已开放端口
sudo firewall-cmd --list-all

## 防火墙开放端口:(开放端口后需重载防火墙)
sudo firewall-cmd --zone=public --add-port=3306/tcp --permanent

配置

服务端配置

需要在服务器开启端口,这次测试部署的是腾讯云,在控制台添加就行。其它服务器商配置可能不同。
下列配置了在端口6352的shadowsocks服务和6353端口的vmess服务,并配置了部份直连规则。更多节点配置见:配置文件

config.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
{
"log": {
"loglevel": "warning",
"access": "/var/log/v2ray/access.log",
"error": "/var/log/v2ray/error.log"
},
"inbounds": [
{
"port": 6352,
"protocol": "shadowsocks",
"settings": {
"method": "aes-128-gcm",
"ota": false,
"password": "gndl"
}
},
{
"port": 6353,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "17449fc0-ac82-4389-bf69-xxxxxxxxxx",
"alterId": 10
}
]
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": [
"baidu.com",
"qq.com",
"bilibili.com",
"geosite:cn"
],
"ip": [
"0.0.0.0/8",
"10.0.0.0/8",
"fc00::/7",
"fe80::/10",
"geoip:cn"
],
"port": "53,443,1000-2000",
"network": "tcp,udp",
"outboundTag": "direct"
}
],
"balancers": []
}
}

客户端配置

config.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
{
"log": {
"access": "access.log",
"error": "error.log",
"loglevel": "warning"
},
"inbounds": [
{
"tag": "proxy",
"port": 10808,
"listen": "127.0.0.1",
"protocol": "socks",
"sniffing": {
"enabled": false,
"destOverride": [
"http",
"tls"
]
},
"settings": {
"auth": "noauth",
"udp": true
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "test.com",
"port": 10465,
"users": [
{
"id": "0909f50b-7519-4720-8911-xxxxxxxxxxx",
"alterId": 0,
"email": "x@qq.com",
"security": "auto"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"allowInsecure": false,
"serverName": "xxx.test.xyz"
},
"wsSettings": {
"path": "/",
"headers": {
"Host": "xxx.test.xyz"
}
}
},
"mux": {
"enabled": true,
"concurrency": 8
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "http"
}
}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"inboundTag": [
"api"
],
"outboundTag": "api"
},
{
"type": "field",
"outboundTag": "proxy",
"domain": [
"geosite:google",
"geosite:telegram",
"geosite:twitter",
"geosite:facebook",
"geosite:github",
"geosite:steam",
"geosite:tumblr",
"geosite:speedtest",
"geosite:bbc",
"geosite:tiktok",
"geosite:netflix",
"geosite:gfw",
"domain:babeljs.cn",
"domain:codepen.io"
]
},
{
"type": "field",
"outboundTag": "direct",
"domain": [
"geosite:cn"
]
},
{
"type": "field",
"outboundTag": "direct",
"ip": [
"geoip:private"
]
},
{
"type": "field",
"outboundTag": "block",
"domain": [
"geosite:category-ads-all"
]
},
{
"type": "field",
"outboundTag": "direct",
"ip": [
"geoip:private"
]
},
{
"type": "field",
"outboundTag": "direct",
"ip": [
"geoip:cn"
]
},
{
"type": "field",
"outboundTag": "direct",
"domain": [
"geosite:cn"
]
}
]
}
}
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×