From 84a5e27c05aec46207c3cce150e45667ca82dd46 Mon Sep 17 00:00:00 2001 From: Eamon-meng <17516219072@163.com> Date: Fri, 8 May 2026 11:37:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E5=8F=96IP=E6=B7=BB=E5=8A=A0=E4=B8=BB?= =?UTF-8?q?=E6=9C=BA=E6=A0=BC=E5=BC=8F=E9=80=89=E9=A1=B9=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/actions/channel.ts | 2 + src/app/(api)/proxies/route.ts | 29 +++++++++++++- .../(home)/docs/(product)/api-docs/page.md | 40 +++++++++++++++++-- src/components/composites/extract/index.tsx | 33 ++++++++++++--- 5 files changed, 95 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 987247e..b5fe71d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lanhu-web", - "version": "1.11.0", + "version": "1.12.0", "private": true, "scripts": { "dev": "next dev -H 0.0.0.0 --turbopack", diff --git a/src/actions/channel.ts b/src/actions/channel.ts index 3f66f0a..3dd2c13 100644 --- a/src/actions/channel.ts +++ b/src/actions/channel.ts @@ -17,6 +17,7 @@ export async function listChannels(props: { } type CreateChannelsResp = { + ip: string host: string port: string username?: string @@ -31,6 +32,7 @@ export async function createChannels(params: { prov?: string city?: string isp?: number + host_format?: number }) { return callPublic('/api/channel/create', params) } diff --git a/src/app/(api)/proxies/route.ts b/src/app/(api)/proxies/route.ts index aaf7597..06826e7 100644 --- a/src/app/(api)/proxies/route.ts +++ b/src/app/(api)/proxies/route.ts @@ -23,6 +23,7 @@ export async function GET(req: NextRequest) { const prov = params.get('a') || undefined const city = params.get('b') || undefined const isp = params.get('s') || undefined + const hostFormat = params.get('rh') || 'domain' const result = await createChannels({ resource_id: Number(resource_id), @@ -32,7 +33,9 @@ export async function GET(req: NextRequest) { prov, city, isp: Number(isp), + host_format: hostFormat === 'domain' ? 1 : 2, }) + if (!result.success) { throw new Error(result.message) } @@ -46,10 +49,32 @@ export async function GET(req: NextRequest) { switch (format) { case 'json': - return NextResponse.json(result.data) + if (hostFormat === 'domain') { + const domainFormatData = result.data.map(item => ({ + host: item.host, + port: item.port, + ...(item.username && item.password ? {username: item.username, password: item.password} : {}), + })) + return NextResponse.json(domainFormatData) + } + else { + const ipFormatData = result.data.map(item => ({ + ip: item.ip, + port: item.port, + ...(item.username && item.password ? {username: item.username, password: item.password} : {}), + })) + return NextResponse.json(ipFormatData) + } case 'text': const text = result.data.map((item) => { - const list = [item.host, item.port] + let hostValue: string + if (hostFormat === 'domain') { + hostValue = item.host + } + else { + hostValue = item.ip + } + const list = [hostValue, String(item.port)] if (item.username && item.password) { list.push(item.username) list.push(item.password) diff --git a/src/app/(home)/docs/(product)/api-docs/page.md b/src/app/(home)/docs/(product)/api-docs/page.md index 28ed9e9..a4c8eae 100644 --- a/src/app/(home)/docs/(product)/api-docs/page.md +++ b/src/app/(home)/docs/(product)/api-docs/page.md @@ -14,7 +14,8 @@ | b | string | 否 | 归属地城市。默认全局随机 | | s | string | 否 | 归属地运营商。默认全局随机 | | d | string | 否 | 是否去重:1 - 是,0 - 否。默认为是 | -| rt | string | 否 | 返回类型:1 - TXT,2 - JSON。默认 TXT | +| rt | string | 否 | 返回类型:1 - TXT,2 - JSON。默认 TXT +| rh | string | 否 | 返回时主机字段的格式:1 - 域名,2 - IP。默认为域名 | | rs | number[] | 否 | 返回时要使用的分隔符,值为该字符的 ascii 编码,可以有多个字符,多个字符用半角逗号连接。默认为 13,10,即回车 + 换行(\r\n) | | rb | number[] | 否 | 返回时要使用的换行符,值为该字符的 ascii 编码,可以有多个字符,多个字符用半角逗号连接。默认为 124,即垂直线( \| ) | | n | number | 否 | 提取数量。默认为 1 | @@ -33,11 +34,11 @@ | password | string | 代理服务器密码(仅在认证类型为密码时返回) | -## 示例 +## 示例1: ### 请求示例 -```http +```http GET https://lanhuip.com/api/extract?i=1&t=2&a=广东省&b=广州市&s=移动&d=1&rt=2&n=3 ``` @@ -65,3 +66,36 @@ GET https://lanhuip.com/api/extract?i=1&t=2&a=广东省&b=广州市&s=移动&d=1 } ] ``` + +## 示例2: + +### 请求示例 + +```http +GET https://lanhuip.com/api/extract?i=24&t=1&a=广东省&b=广州市&d=1&rt=text&rh=ip&rs=124&rb=13%2C10&n=1 +``` + +### 响应示例 + +```json +[ + { + "ip": "127.0.0.1", + "port": 20000, + "username": "user1", + "password": "pass1" + }, + { + "ip": "127.0.0.1", + "port": 20001, + "username": "user2", + "password": "pass2" + }, + { + "ip": "127.0.0.1", + "port": 20002, + "username": "user3", + "password": "pass3" + } +] +``` diff --git a/src/components/composites/extract/index.tsx b/src/components/composites/extract/index.tsx index 496d1a3..1143c8f 100644 --- a/src/components/composites/extract/index.tsx +++ b/src/components/composites/extract/index.tsx @@ -28,10 +28,11 @@ const schema = z.object({ city: z.string().optional(), regionType: z.enum(['unlimited', 'specific']).default('unlimited'), isp: z.enum(['all', '1', '2', '3'], {required_error: '请选择运营商'}), - proto: z.enum(['all', '1', '2', '3'], {required_error: '请选择协议'}), + proto: z.enum(['all', '1', '2'], {required_error: '请选择协议'}), authType: z.enum(['1', '2'], {required_error: '请选择认证方式'}), distinct: z.enum(['1', '0'], {required_error: '请选择去重选项'}), format: z.enum(['text', 'json'], {required_error: '请选择导出格式'}), + hostFormat: z.enum(['domain', 'ip'], {required_error: '请选择主机格式'}), separator: z.string({required_error: '请选择分隔符'}), breaker: z.string({required_error: '请选择换行符'}), count: z.number({required_error: '请输入有效的数量'}).min(1), @@ -53,6 +54,7 @@ export default function Extract(props: ExtractProps) { authType: '1', count: 1, distinct: '1', + hostFormat: 'domain', format: 'text', breaker: '13,10', separator: '124', @@ -163,12 +165,12 @@ const FormFields = memo(() => { HTTP - + {/* HTTPS - + */} - + SOCKS5 @@ -233,6 +235,26 @@ const FormFields = memo(() => { )} + {/* 主机格式 */} + + {({id, field}) => ( + + + + 域名 + + + + IP + + + )} + + {/* 分隔符 */} {({id, field}) => ( @@ -648,7 +670,7 @@ function ApplyLink() { } function link(values: Schema) { - const {resource, prov, city, isp, proto, authType, distinct, format: formatType, separator, breaker, count} = values + const {resource, prov, city, isp, proto, authType, distinct, format: formatType, hostFormat, separator, breaker, count} = values const sp = new URLSearchParams() if (resource) sp.set('i', String(resource)) @@ -660,6 +682,7 @@ function link(values: Schema) { if (isp != 'all') sp.set('s', isp) sp.set('d', distinct) sp.set('rt', formatType) + sp.set('rh', hostFormat) sp.set('rs', separator) sp.set('rb', breaker) sp.set('n', String(count))