VKProxy 是使用c#开发的基于 Kestrel 实现 L4/L7的代理

有兴趣的同学点个赞呗

目前已经在写文档了, 文档在 https://fs7744.github.io/VKProxy.Doc/docs/introduction.html (未完成全部)

UI配置站点也在开发ing了,会基于 etcd 作为配置源,主要考虑配置文件分发会导致大家在部署多实例场景有难度

docker 会在 UI配置站点 完成后再完善到文档

这里列举一下基本的配置

安装

自行构建

VKProxy 有很多扩展点可以定制化大家所需特制化需求,所以有相关需求时推荐自行构建

创建一个项目,然后选取所需package安装

dotnet add package VKProxy
dotnet add package VKProxy.Storages.Etcd

配置程序

using Microsoft.Extensions.Hosting;
using ProxyDemo; var app = Host.CreateDefaultBuilder(args)
.UseReverseProxy()
.ConfigureServices(i =>
{
// 默认加载appsettings.json 配置
// 如需采用 etcd 作为配置源,请设置环境变量`ETCD_CONNECTION_STRING`并使用如下代码
// i.UseEtcdConfigFromEnv();
})
.Build(); await app.RunAsync();

配置代理

假如使用 appsettings.json 进行配置, 这里列举一个http1的代理配置

(配置项很多,可参考后续具体配置项说明, 也可以考虑使用 UI配置站点)

{
"ReverseProxy": {
// 监听端口 127.0.0.1:5001
"Listen": {
"http": {
"Protocols": [
"Http1"
],
"Address": [
"127.0.0.1:5001"
]
}
},
// 设置路由匹配任意 com 结尾的host,以及 url开头为 /ws 并且 method 为 GET的请求
"Routes": {
"HTTPTEST": {
"Match": {
"Hosts": [
"*com"
],
"Paths": [
"/ws*"
],
"Statement": "Method = 'GET'"
},
"ClusterId": "apidemo",
"Timeout": "00:10:11"
}
},
// 配置匹配请求转发到对应目标地址,并且通过主动健康检查保证服务稳定
"Clusters": {
"apidemo": {
"LoadBalancingPolicy": "RoundRobin",
"HealthCheck": {
"Active": {
"Enable": true,
"Policy": "Http",
"Path": "/test",
"Query": "?a=d",
"Method": "post"
}
},
"Destinations": [
{
"Address": "http://127.0.0.1:1104"
},
{
"Address": "https://google.com"
}
]
}
}
}
}

不同监听场景如何配置

[!WARNING]

虽然可以在运行时动态变更监听,但是目前Kestrel在终止监听时会等待已有连接结束,以降低对用户影响,达到优雅关闭的效果

所以在动态变更时不一定能实时生效,一定会等待已访问连接结束(超时时间1秒,超时将强制关闭),如果频繁变化,可能会导致问题

监听 UDP

这里展示如何 将 127.0.0.1:5000 UDP 代理到 127.0.0.1:11000, 同时只接受服务端最多返回一个 udp 包

{
"ReverseProxy": {
"Listen": {
// Listen id : udptest
"udptest": {
"Protocols": [ "UDP" ], // 协议选择 UDP
"Address": [ "127.0.0.1:5000" ], // 监听地址
"RouteId": "udpTestRoute" // UDP 必填路由,因为不像http 有host等协议参数能确定目的地址
}
},
"Routes": {
// Routes id : udpTestRoute
"udpTestRoute": {
"ClusterId": "udpTestCluster", // udp 目的地址 id
"UdpResponses": 1, // 只接受服务端最多返回一个 udp 包
"Timeout": "00:00:11" // 超时时间 11 秒, 包含从udp包 发送到 目的地址和 等待以及返回 服务端udp包的总共时间
}
},
"Clusters": {
// Clusters id : udpTestCluster
"udpTestCluster": {
"Destinations": [
{
"Address": "127.0.0.1:11000" //目的地址
}
]
}
}
}
}

监听 TCP

这里展示如何 将 127.0.0.1:5000 TCP 代理到 https://google.com

{
"ReverseProxy": {
"Listen": {
// Listen id : tcpTest
"tcpTest": {
"Protocols": [ "TCP" ], // 协议选择 TCP
"Address": [ "127.0.0.1:5000" ], // 监听地址
"RouteId": "tcpTestRoute" // tcp 必填路由,因为不像http 有host等协议参数能确定目的地址
}
},
"Routes": {
// Routes id : tcpTestRoute
"tcpTestRoute": {
"ClusterId": "tcpTestCluster", // tcp 目的地址 id
"Timeout": "00:00:11" // 超时时间 11 秒,
}
},
"Clusters": {
// Clusters id : tcpTestCluster
"tcpTestCluster": {
"Destinations": [
{
"Address": "https://google.com" //目的地址
}
]
}
}
}
}

监听 SNI 代理 (Passthrough)

这里展示如何 将 127.0.0.1:5000 TCP SNI

并通过ssl握手时的 host 路由匹配代理到 https://google.com, 但这里我们配置不在proxy端处理ssl,而是交由后端服务自行处理

{
"ReverseProxy": {
"Listen": {
// Listen id : tcpTest
"tcpTest": {
"Protocols": [
"TCP"
], // 协议选择 TCP
"Address": [
"127.0.0.1:5000"
], // 监听地址
"UseSni": true // 开启 sni 代理,由于采用 公用 sni ,所以不必配置RouteId
}
},
"Sni": {
"sniPassthroughTest": {
// 这里配置 所有 com 结尾的请求都会路由到 tcpTestRoute
"Host": [
"*com"
],
"Passthrough": true, // 配置不在proxy端处理ssl,而是交由后端服务自行处理
"RouteId": "tcpTestRoute"
},
},
"Routes": {
// Routes id : tcpTestRoute
"tcpTestRoute": {
"ClusterId": "tcpTestCluster", // tcp 目的地址 id
"Timeout": "00:00:11" // 超时时间 11 秒,
}
},
"Clusters": {
// Clusters id : tcpTestCluster
"tcpTestCluster": {
"Destinations": [
{
"Address": "https://google.com" //目的地址
}
]
}
}
}
}

监听 SNI 代理 (ssl)

这里展示如何 将 127.0.0.1:5000 TCP SNI

并通过ssl握手时的 host 路由匹配代理到 http://google.com, 但这里我们配置在proxy端处理ssl,并且由于是tcp代理,所以后端服务无法使用 https, 因为已经被proxy 解密了,http请求的场景只能配置后端服务为 http了

{
"ReverseProxy": {
"Listen": {
// Listen id : tcpTest
"tcpTest": {
"Protocols": [
"TCP"
], // 协议选择 TCP
"Address": [
"127.0.0.1:5000"
], // 监听地址
"UseSni": true // 开启 sni 代理,由于采用 公用 sni ,所以不必配置RouteId
}
},
"Sni": {
"sniPassthroughTest": {
// 这里配置 所有 com 结尾的请求都会路由到 tcpTestRoute
"Host": [
"*com"
],
"CheckCertificateRevocation": false, // 不进行证书校验, 因为这里配置的是自签证书,只是用于测试
// 这里配置 PEM 格式证书, 这样配置便于更换,如果使用机器上的证书文件,有一些场景比如 docker 大家就很不方便了
"Certificate": {
"PEM": "-----BEGIN CERTIFICATE-----\nMIIFCzCCAvOgAwIBAgIUAi7DqcEn4EsBm1lN4UcmmuxWPq0wDQYJKoZIhvcNAQEL\nBQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIxMDIyNjE4MzI0OVoYDzIxMjEw\nMjAyMTgzMjQ5WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQDI5+DbDLpVmRFFB9YR1NwAbdPzf7cV8RB32pNVHzLj\niJ9LNSq8yvI/k6xD3p8XHVJEC3TGMuOVK4Cn277nX9KSU/7lELMlz+yGikwli3aI\nu4A7NE84ACfR6ZFelAGcGr2nMze6K2YDwhhqG8SUBIhAjzjIXSf2+cv0Cq38cEX1\nWKy1h5xJm7FwuKlZsHmJw5Osk+8mFgHJ5TmKqJYtVd7b/ytAmeM2ByZ4eVCZ31rR\nELKZ2uEWoCImLCtCfohxEnhrLm09yB7JrbbT/3JXHXyQUn3kGMczgwL/IZZwqtAf\nE4SiHVLI3cFwO3VJjpRfAbg3xFbxwzhmdlri3WsKT3iEp3P08WPi6dL7WF+PjpMl\nd9RZ587NBSqCmVfgBjY05wEcONSPyPY1gi5ZBDBm6J23feAOgZ8AZu/RKdAVgYBu\nKr6o6ZKqsJ+U+M5cwrXw/Rv78YQyr9ZlfKALbybMKMrYuc9DqbPGBbryLxklh9kN\nwMJvt8FHEcmlbT5BsZJmm7JztPouN7mxMy1ZVJlGreyPD0mxET+O4DCz7UsA2CvB\npKzLcRRHKKNbCwaeV/1UJKiyg4QWDGltlIKkIEhppv2vspl0Gh7xpZISJuWtmWiJ\no03zSr7NUNvXRY3pmNQXad7PHanVyTCopCCpTiAQljDTTb803NGyKBHx3cz17HU9\nxQIDAQABo1MwUTAdBgNVHQ4EFgQUGyQOi+8yPBZziF7ruCfQB4ooTMUwHwYDVR0j\nBBgwFoAUGyQOi+8yPBZziF7ruCfQB4ooTMUwDwYDVR0TAQH/BAUwAwEB/zANBgkq\nhkiG9w0BAQsFAAOCAgEAHf+FN6rHdZJPdmUO1skpS9iVgXrKWGwo20Qrd3MttKfk\nxzFpOZLBEyn/qWmZe1YQqdcm4Yd7OjnKRb62zwE8gyTJlaA30qXGoJZrouWEAsWZ\n2//2h/Ju6XNy47p5F2UKAKqqGcSaDy9HEQF0wNwRz45LKYlJE7v7eDqo2TOampoH\nUXNRF9lKI4o+CKkSRquoqGXfw6GJmnxrozTzWl00igSXrX3+HkiKHNOgzaOoS+pP\nnFl/HI/jOFYh8AG/18U5iFBSTjXiyXmFvkb4309c188fJd1UMOVY1tbcfFWSftnL\nYbk8UmGagtI9S8ExuQvk34TGDwj0vdKGiTBdL/qQ1vzxqLo2U7fHRcktSo27Ogtp\nJCzfyXKb41Cu4VOmzllTlhbg/p68rEeYcVIeZl86Yh3bFZNVpvHW9vzn8iLIXpGf\nnyt/XXG0cgkTPeWZ+zTPHLx/9YZBXViUuXobXLeUhueCaWGHYPkzKcV1c1B9oJjc\n/3JWbJVERFxMGgJpQUrTMerUCmY3C2lfPBm48ZmPCjmUUdWsh5vu2pVe+3hBIFeb\nY/kkOuRqAmiW+EmjFNQNdcxsDstd1AeipapPSH0TLWTqvAs8MndoNmfHyOFomV38\nEls5LL5Pomm27oVq6JM1geF1jKShAnO/w/dlRXcB0PFJIlpWKpw7OE5qqPpoiZY=\n-----END CERTIFICATE-----",
"PEMKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\n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\nBlK3Zix8WqtE14P/MNzfaA==\n-----END ENCRYPTED PRIVATE KEY-----",
"Password": "testPassword"
},
"RouteId": "tcpTestRoute"
},
},
"Routes": {
// Routes id : tcpTestRoute
"tcpTestRoute": {
"ClusterId": "tcpTestCluster", // tcp 目的地址 id
"Timeout": "00:00:11" // 超时时间 11 秒,
}
},
"Clusters": {
// Clusters id : tcpTestCluster
"tcpTestCluster": {
"Destinations": [
{
"Address": "http://google.com" //目的地址 由于是tcp代理,所以后端服务无法使用 https, 因为已经被proxy 解密了,http请求的场景只能配置后端服务为 http了
}
]
}
}
}
}

监听 http 代理

这里展示如何 将 127.0.0.1:5000 http1 协议 ,(其他版本需要证书,所以这里单独展示配置,以便大家对比)

并通过 host 路由匹配代理到 http://google.com

{
"ReverseProxy": {
"Listen": {
// Listen id : httpTest
"httpTest": {
"Protocols": [
"HTTP1"
], // 协议选择 HTTP1
"Address": [
"127.0.0.1:5000"
], // 监听地址
},
},
"Routes": {
// Routes id : httpTestRoute
"httpTestRoute": {
// 配置 http 请求如何匹配
"Match": {
"Hosts": [ "*com" ], // 匹配 host 为 com 结尾的
"Paths": [ "/ws*" ], // url 匹配 /ws 开头的
"Statement": "Method = 'GET'" // http method 匹配 GET, 这里提供 类似 sql 中 where 的简单表达式写法,当然有一些限制,请参见 Statement 说明
},
"ClusterId": "httpTestCluster", // 目的地址 id
"Timeout": "00:00:11" // 超时时间 11 秒,
}
},
"Clusters": {
// Clusters id : httpTestCluster
"httpTestCluster": {
"Destinations": [
{
"Address": "http://google.com"
}
]
}
}
}
}

监听 https (证书通过sni匹配) 代理

这里展示如何 将 127.0.0.1:5000 http1 / http2 协议 ,证书通过sni匹配, http3 因为目前 quic 底层实现限制, 无法在运行时动态切换证书,所以无法在sni 配置

并通过 host 路由匹配代理到 http://google.com

{
"ReverseProxy": {
"Listen": {
// Listen id : httpTest
"httpTest": {
"Protocols": [
"HTTP1","HTTP2"
], // 协议选择 HTTP1 HTTP2
"Address": [
"127.0.0.1:5000"
], // 监听地址
"UseSni": true // 表明 启用 https
}
},
"Routes": {
// Routes id : httpTestRoute
"httpTestRoute": {
// 配置 http 请求如何匹配
"Match": {
"Hosts": [ "*com" ], // 匹配 host 为 com 结尾的
"Paths": [ "/ws*" ], // url 匹配 /ws 开头的
"Statement": "Method = 'GET'" // http method 匹配 GET, 这里提供 类似 sql 中 where 的简单表达式写法,当然有一些限制,请参见 Statement 说明
},
"ClusterId": "httpTestCluster", // 目的地址 id
"Timeout": "00:00:11" // 超时时间 11 秒,
}
},
"Clusters": {
// Clusters id : httpTestCluster
"httpTestCluster": {
"Destinations": [
{
"Address": "http://google.com"
}
]
}
},
"Sni": {
"sniComTest": {
// 这里配置 所有 com 结尾的SSL握手请求都会匹配到如下证书
"Host": [
"*com"
],
"CheckCertificateRevocation": false, // 不进行证书校验, 因为这里配置的是自签证书,只是用于测试
// 这里配置 PEM 格式证书, 这样配置便于更换,如果使用机器上的证书文件,有一些场景比如 docker 大家就很不方便了
"Certificate": {
"PEM": "-----BEGIN CERTIFICATE-----\nMIIFCzCCAvOgAwIBAgIUAi7DqcEn4EsBm1lN4UcmmuxWPq0wDQYJKoZIhvcNAQEL\nBQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIxMDIyNjE4MzI0OVoYDzIxMjEw\nMjAyMTgzMjQ5WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQDI5+DbDLpVmRFFB9YR1NwAbdPzf7cV8RB32pNVHzLj\niJ9LNSq8yvI/k6xD3p8XHVJEC3TGMuOVK4Cn277nX9KSU/7lELMlz+yGikwli3aI\nu4A7NE84ACfR6ZFelAGcGr2nMze6K2YDwhhqG8SUBIhAjzjIXSf2+cv0Cq38cEX1\nWKy1h5xJm7FwuKlZsHmJw5Osk+8mFgHJ5TmKqJYtVd7b/ytAmeM2ByZ4eVCZ31rR\nELKZ2uEWoCImLCtCfohxEnhrLm09yB7JrbbT/3JXHXyQUn3kGMczgwL/IZZwqtAf\nE4SiHVLI3cFwO3VJjpRfAbg3xFbxwzhmdlri3WsKT3iEp3P08WPi6dL7WF+PjpMl\nd9RZ587NBSqCmVfgBjY05wEcONSPyPY1gi5ZBDBm6J23feAOgZ8AZu/RKdAVgYBu\nKr6o6ZKqsJ+U+M5cwrXw/Rv78YQyr9ZlfKALbybMKMrYuc9DqbPGBbryLxklh9kN\nwMJvt8FHEcmlbT5BsZJmm7JztPouN7mxMy1ZVJlGreyPD0mxET+O4DCz7UsA2CvB\npKzLcRRHKKNbCwaeV/1UJKiyg4QWDGltlIKkIEhppv2vspl0Gh7xpZISJuWtmWiJ\no03zSr7NUNvXRY3pmNQXad7PHanVyTCopCCpTiAQljDTTb803NGyKBHx3cz17HU9\nxQIDAQABo1MwUTAdBgNVHQ4EFgQUGyQOi+8yPBZziF7ruCfQB4ooTMUwHwYDVR0j\nBBgwFoAUGyQOi+8yPBZziF7ruCfQB4ooTMUwDwYDVR0TAQH/BAUwAwEB/zANBgkq\nhkiG9w0BAQsFAAOCAgEAHf+FN6rHdZJPdmUO1skpS9iVgXrKWGwo20Qrd3MttKfk\nxzFpOZLBEyn/qWmZe1YQqdcm4Yd7OjnKRb62zwE8gyTJlaA30qXGoJZrouWEAsWZ\n2//2h/Ju6XNy47p5F2UKAKqqGcSaDy9HEQF0wNwRz45LKYlJE7v7eDqo2TOampoH\nUXNRF9lKI4o+CKkSRquoqGXfw6GJmnxrozTzWl00igSXrX3+HkiKHNOgzaOoS+pP\nnFl/HI/jOFYh8AG/18U5iFBSTjXiyXmFvkb4309c188fJd1UMOVY1tbcfFWSftnL\nYbk8UmGagtI9S8ExuQvk34TGDwj0vdKGiTBdL/qQ1vzxqLo2U7fHRcktSo27Ogtp\nJCzfyXKb41Cu4VOmzllTlhbg/p68rEeYcVIeZl86Yh3bFZNVpvHW9vzn8iLIXpGf\nnyt/XXG0cgkTPeWZ+zTPHLx/9YZBXViUuXobXLeUhueCaWGHYPkzKcV1c1B9oJjc\n/3JWbJVERFxMGgJpQUrTMerUCmY3C2lfPBm48ZmPCjmUUdWsh5vu2pVe+3hBIFeb\nY/kkOuRqAmiW+EmjFNQNdcxsDstd1AeipapPSH0TLWTqvAs8MndoNmfHyOFomV38\nEls5LL5Pomm27oVq6JM1geF1jKShAnO/w/dlRXcB0PFJIlpWKpw7OE5qqPpoiZY=\n-----END CERTIFICATE-----",
"PEMKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\n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\nBlK3Zix8WqtE14P/MNzfaA==\n-----END ENCRYPTED PRIVATE KEY-----",
"Password": "testPassword"
}
}
},
}
}

监听 http3 代理

这里展示如何 将 127.0.0.1:5000 http1 / http2 / http3 协议 , http3 因为目前 quic 底层实现限制, 无法在运行时动态切换证书,所以特殊指定证书配置,也因此 127.0.0.1:5000 只能匹配这一证书,无法提供sni动态匹配证书的能力

并通过 host 路由匹配代理到 http://google.com

{
"ReverseProxy": {
"Listen": {
// Listen id : httpTest
"httpTest": {
"Protocols": [
"HTTP1","HTTP2", "HTTP3"
], // 协议选择 HTTP1 HTTP2 HTTP3
"Address": [
"127.0.0.1:5000"
], // 监听地址
"UseSni": true, // 表明 启用 https,
"SniId": "sniComTest" // http3 因为目前 quic 底层实现限制, 无法在运行时动态切换证书 所以特殊指定证书配置,也因此 127.0.0.1:5000 只能匹配这一证书,无法提供sni动态匹配证书的能力
}
},
"Routes": {
// Routes id : httpTestRoute
"httpTestRoute": {
// 配置 http 请求如何匹配
"Match": {
"Hosts": [ "*com" ], // 匹配 host 为 com 结尾的
"Paths": [ "/ws*" ], // url 匹配 /ws 开头的
"Statement": "Method = 'GET'" // http method 匹配 GET, 这里提供 类似 sql 中 where 的简单表达式写法,当然有一些限制,请参见 Statement 说明
},
"ClusterId": "httpTestCluster", // 目的地址 id
"Timeout": "00:00:11" // 超时时间 11 秒,
}
},
"Clusters": {
// Clusters id : httpTestCluster
"httpTestCluster": {
"Destinations": [
{
"Address": "http://google.com"
}
]
}
},
"Sni": {
"sniComTest": {
// 这里配置 所有 com 结尾的SSL握手请求都会匹配到如下证书
"Host": [
"*com"
],
"CheckCertificateRevocation": false, // 不进行证书校验, 因为这里配置的是自签证书,只是用于测试
// 这里配置 PEM 格式证书, 这样配置便于更换,如果使用机器上的证书文件,有一些场景比如 docker 大家就很不方便了
"Certificate": {
"PEM": "-----BEGIN CERTIFICATE-----\nMIIFCzCCAvOgAwIBAgIUAi7DqcEn4EsBm1lN4UcmmuxWPq0wDQYJKoZIhvcNAQEL\nBQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIxMDIyNjE4MzI0OVoYDzIxMjEw\nMjAyMTgzMjQ5WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQDI5+DbDLpVmRFFB9YR1NwAbdPzf7cV8RB32pNVHzLj\niJ9LNSq8yvI/k6xD3p8XHVJEC3TGMuOVK4Cn277nX9KSU/7lELMlz+yGikwli3aI\nu4A7NE84ACfR6ZFelAGcGr2nMze6K2YDwhhqG8SUBIhAjzjIXSf2+cv0Cq38cEX1\nWKy1h5xJm7FwuKlZsHmJw5Osk+8mFgHJ5TmKqJYtVd7b/ytAmeM2ByZ4eVCZ31rR\nELKZ2uEWoCImLCtCfohxEnhrLm09yB7JrbbT/3JXHXyQUn3kGMczgwL/IZZwqtAf\nE4SiHVLI3cFwO3VJjpRfAbg3xFbxwzhmdlri3WsKT3iEp3P08WPi6dL7WF+PjpMl\nd9RZ587NBSqCmVfgBjY05wEcONSPyPY1gi5ZBDBm6J23feAOgZ8AZu/RKdAVgYBu\nKr6o6ZKqsJ+U+M5cwrXw/Rv78YQyr9ZlfKALbybMKMrYuc9DqbPGBbryLxklh9kN\nwMJvt8FHEcmlbT5BsZJmm7JztPouN7mxMy1ZVJlGreyPD0mxET+O4DCz7UsA2CvB\npKzLcRRHKKNbCwaeV/1UJKiyg4QWDGltlIKkIEhppv2vspl0Gh7xpZISJuWtmWiJ\no03zSr7NUNvXRY3pmNQXad7PHanVyTCopCCpTiAQljDTTb803NGyKBHx3cz17HU9\nxQIDAQABo1MwUTAdBgNVHQ4EFgQUGyQOi+8yPBZziF7ruCfQB4ooTMUwHwYDVR0j\nBBgwFoAUGyQOi+8yPBZziF7ruCfQB4ooTMUwDwYDVR0TAQH/BAUwAwEB/zANBgkq\nhkiG9w0BAQsFAAOCAgEAHf+FN6rHdZJPdmUO1skpS9iVgXrKWGwo20Qrd3MttKfk\nxzFpOZLBEyn/qWmZe1YQqdcm4Yd7OjnKRb62zwE8gyTJlaA30qXGoJZrouWEAsWZ\n2//2h/Ju6XNy47p5F2UKAKqqGcSaDy9HEQF0wNwRz45LKYlJE7v7eDqo2TOampoH\nUXNRF9lKI4o+CKkSRquoqGXfw6GJmnxrozTzWl00igSXrX3+HkiKHNOgzaOoS+pP\nnFl/HI/jOFYh8AG/18U5iFBSTjXiyXmFvkb4309c188fJd1UMOVY1tbcfFWSftnL\nYbk8UmGagtI9S8ExuQvk34TGDwj0vdKGiTBdL/qQ1vzxqLo2U7fHRcktSo27Ogtp\nJCzfyXKb41Cu4VOmzllTlhbg/p68rEeYcVIeZl86Yh3bFZNVpvHW9vzn8iLIXpGf\nnyt/XXG0cgkTPeWZ+zTPHLx/9YZBXViUuXobXLeUhueCaWGHYPkzKcV1c1B9oJjc\n/3JWbJVERFxMGgJpQUrTMerUCmY3C2lfPBm48ZmPCjmUUdWsh5vu2pVe+3hBIFeb\nY/kkOuRqAmiW+EmjFNQNdcxsDstd1AeipapPSH0TLWTqvAs8MndoNmfHyOFomV38\nEls5LL5Pomm27oVq6JM1geF1jKShAnO/w/dlRXcB0PFJIlpWKpw7OE5qqPpoiZY=\n-----END CERTIFICATE-----",
"PEMKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\n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\nBlK3Zix8WqtE14P/MNzfaA==\n-----END ENCRYPTED PRIVATE KEY-----",
"Password": "testPassword"
}
}
},
}
}

已经在为VKProxy写UI配置站点和文档了的更多相关文章

  1. Swagger UI教程 API 文档神器 搭配Node使用 web api 接口文档 (转)

    http://www.68idc.cn/help/makewebs/qitaasks/20160621620667.html 两种方案 一.Swagger 配置 web Api 接口文档美化 二.通过 ...

  2. 【Xamarin挖墙脚系列:代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧(转)】

    正愁如何选择构建项目中的视图呢,现在官方推荐画板 Storybord...但是好像 xib貌似更胜一筹.以前的老棒子总喜欢装吊,用代码写....用代码堆一个HTML页面不知道你们尝试过没有.等页面做出 ...

  3. 代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧

    近期接触了几个刚入门的iOS学习者,他们之中存在一个普遍和困惑和疑问.就是应该怎样制作UI界面.iOS应用是非常重视用户体验的,能够说绝大多数的应用成功与否与交互设计以及UI是否美丽易用有着非常大的关 ...

  4. [cocos2dx笔记012]一定简易的UI配置类

    使用cocostudio能够装载编辑好的UI,可是过于复杂.特别是在加截UI后,发现触屏事件有些问题. 假设直接使用程序写死载入UI又过于麻烦.花点时间,添加了一个基于ini的UI配置类,眼下仅仅实现 ...

  5. 关于代码手写UI,xib和StoryBoard

    代码手写UI 这种方法经常被学院派的极客或者依赖多人合作的大型项目大规模使用.Geek们喜欢用代码构建UI,是因为代码是键盘敲出来的,这样可以做到不开IB,手不离开键盘就完成工作,可以专注于编码环境, ...

  6. 关于如何写UI及屏幕适配的一些技巧

    因为公司开启了一个新的iOS项目, 所以近期比较忙, 没有更新博客,今天打算总结一下关于UI布局及屏幕适配的一些实战技巧,尤其使用纯代码,会对提升效率及代码易于维护等方面有明显帮助,这里提到的没有使用 ...

  7. Apache配置站点根目录、用户目录及页面访问属性

    一.配置站点根目录及页面访问属性 DocumentRoot "/www/htdoc" <Directory "/www/htdoc"> Option ...

  8. EDIT Ini写Ini配置

    EDIT Ini写Ini配置  uses IniFiles; {$R *.dfm}   function IniFileName:string; begin    Result:=ExtractFil ...

  9. [Intel Edison开发板] 06、Edison开发在linux中烧写、配置、搭建开发环境

    1.前言 linux上烧写.配置.搭建Edison环境,千万不要用默认的setup tool for ubuntu!!! (即使,你用的就是ubuntu) 因为,其默认的工具会从一个坏链接下载配置文件 ...

  10. phpStudy配置站点 解决You don't have permission to access / on this server

    1.配置站点:打开phpStudy->其他选项菜单->站点域名管理 2.配置站点:打开phpStudy->其他选项菜单->打开hosts 3.在apache的配置文件vhost ...

随机推荐

  1. sql 周岁计算

    select  FLOOR(DATEDIFF(DY, substring(身份证字段,7,4), GETDATE()) / 365.25)  age  from [表名]

  2. JUC相关知识点总结

    Java JUC(java.util.concurrent)是Java并发编程的核心工具包,提供了丰富的并发工具类和框架.以下是JUC的主要知识点,按难易程度分类,供你参考: 1. 基础概念与工具类 ...

  3. 青岛oj集训1

    2025/3/4 内容:有向无环图(DAG) 优点:DAG有很多良好性质 拓扑排序 用处:可以根据拓扑序进行dp 这次计算所用的所有边的权值都是有计算过的 一张DAG图肯定有拓扑序(bfs序,dfs序 ...

  4. PHP测试代码执行时间

    https://blog.csdn.net/wyqwclsn/article/details/39930125 非常简单代码开始前加一个$start = microtime(true);代码结束后加一 ...

  5. 结构化语句header nav aside main article section footer

    点击查看代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  6. halo配置踩坑过程小记

    写在最前: ​ 终于搞定了最后的一步域名解析配置,其实动态博客的折腾程度也不低于当时的hexo吧,也可能当时的痛苦过程已经忘了..整理一下思路,记录一下配置过程走过的坑. ​ 我是从hexo用了半年想 ...

  7. Keil中设置显示空白符,并将Tab键使用4个空格代替

    前言 Keil 的默认设置是没有将 Tab 键使用空格代替的,不同的文本编辑器对 Tab 键所占的空格数不同,有占 2 个空格的,也有占 4 个空格的,这就导致同样的代码在不同的编辑器中缩进不同,虽不 ...

  8. mongodb 查看、创建、修改、删除索引

    简介 索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录. 这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询 ...

  9. Supervisor-进程守护工具

    前言 Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启.它是通过fork/exec的方式把这些被管理 ...

  10. php接收json数据

    写php这么些年了,好多知识点都没有总结,来记录一下.毕竟日拱一卒无有尽,功不唐捐终入海. 用php来做APP的接口开发,但是在用postman模拟提交数据的时候$_POST.$_REQUEST都获取 ...