Skip to content

Commit b8318d6

Browse files
author
githubnull
committed
refactor: 模块化拆分httpRequestParser解析器
- 将659行单文件拆分为模块化结构 - types.ts: 类型定义模块 - formatDetector.ts: 格式检测模块 - urlParser.ts: URL解析工具模块 - parsers/: 各格式解析器(curl/powershell/fetch/rawHttp) - formatters/httpFormatter.ts: HTTP格式化模块 - index.ts: 主入口统一导出 - 增强类型安全性,修复潜在undefined问题 - API导入路径保持兼容
1 parent 564618b commit b8318d6

11 files changed

Lines changed: 1312 additions & 658 deletions

File tree

src/frontEnd/src/utils/httpRequestParser.ts

Lines changed: 0 additions & 658 deletions
This file was deleted.
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/**
2+
* HTTP请求解析器 - 格式检测模块
3+
*
4+
* 自动检测输入文本的请求格式类型
5+
*/
6+
7+
import type { RequestFormat } from './types'
8+
9+
/**
10+
* 格式检测规则配置
11+
* 使用优先级排序,先匹配的优先
12+
*/
13+
interface FormatRule {
14+
format: RequestFormat
15+
patterns: RegExp[]
16+
/** 额外的区分规则 */
17+
discriminator?: (input: string) => RequestFormat | null
18+
}
19+
20+
/**
21+
* 格式检测规则列表
22+
*/
23+
const FORMAT_RULES: FormatRule[] = [
24+
// 原始HTTP报文格式 - 最先检测
25+
{
26+
format: 'raw_http',
27+
patterns: [
28+
/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS|TRACE|CONNECT)\s+\S+\s+HTTP\/[\d.]+/i
29+
]
30+
},
31+
// cURL格式 - 需要区分cmd和bash
32+
{
33+
format: 'curl_bash',
34+
patterns: [/^curl\s/i],
35+
discriminator: (input) => {
36+
// cmd格式使用 ^ 作为续行符,或使用特定的双引号模式
37+
if (input.includes('^') || /curl\s+"[^"]*"/i.test(input)) {
38+
return 'curl_cmd'
39+
}
40+
return 'curl_bash'
41+
}
42+
},
43+
// PowerShell格式
44+
{
45+
format: 'powershell',
46+
patterns: [
47+
/^Invoke-WebRequest/i,
48+
/^Invoke-RestMethod/i,
49+
/^\$session\s*=\s*New-Object/i,
50+
/^iwr\s/i
51+
]
52+
},
53+
// fetch格式 - 需要区分js和nodejs
54+
{
55+
format: 'fetch_js',
56+
patterns: [/^fetch\s*\(/i],
57+
discriminator: (input) => {
58+
// Node.js fetch 通常有 require 或 import
59+
if (
60+
/require\s*\(\s*['"]node-fetch['"]\s*\)/i.test(input) ||
61+
/import\s+.*from\s+['"]node-fetch['"]/i.test(input)
62+
) {
63+
return 'fetch_nodejs'
64+
}
65+
return 'fetch_js'
66+
}
67+
}
68+
]
69+
70+
/**
71+
* 检测输入的格式类型
72+
*
73+
* @param input - 输入文本
74+
* @returns 检测到的格式类型
75+
*
76+
* @example
77+
* detectFormat('curl -X POST https://example.com')
78+
* // => 'curl_bash'
79+
*
80+
* detectFormat('GET /api HTTP/1.1\nHost: example.com')
81+
* // => 'raw_http'
82+
*/
83+
export function detectFormat(input: string): RequestFormat {
84+
if (!input || typeof input !== 'string') {
85+
return 'unknown'
86+
}
87+
88+
const trimmed = input.trim()
89+
90+
if (!trimmed) {
91+
return 'unknown'
92+
}
93+
94+
// 遍历规则进行匹配
95+
for (const rule of FORMAT_RULES) {
96+
const matched = rule.patterns.some(pattern => pattern.test(trimmed))
97+
98+
if (matched) {
99+
// 如果有区分规则,使用区分规则
100+
if (rule.discriminator) {
101+
const discriminatedFormat = rule.discriminator(trimmed)
102+
if (discriminatedFormat) {
103+
return discriminatedFormat
104+
}
105+
}
106+
return rule.format
107+
}
108+
}
109+
110+
return 'unknown'
111+
}
112+
113+
/**
114+
* 检查是否为已知格式
115+
*/
116+
export function isKnownFormat(format: RequestFormat): boolean {
117+
return format !== 'unknown'
118+
}
119+
120+
/**
121+
* 检查是否为cURL格式(包括cmd和bash)
122+
*/
123+
export function isCurlFormat(format: RequestFormat): boolean {
124+
return format === 'curl_bash' || format === 'curl_cmd'
125+
}
126+
127+
/**
128+
* 检查是否为fetch格式(包括js和nodejs)
129+
*/
130+
export function isFetchFormat(format: RequestFormat): boolean {
131+
return format === 'fetch_js' || format === 'fetch_nodejs'
132+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* HTTP请求解析器 - HTTP格式化模块
3+
*
4+
* 提供将解析结果转换为各种格式的功能
5+
*/
6+
7+
import type { ParsedHttpRequest, RequestFormat } from '../types'
8+
import { FORMAT_DISPLAY_NAMES } from '../types'
9+
import { parseRawHttp } from '../parsers/rawHttpParser'
10+
11+
/**
12+
* 将解析后的请求转换为原始HTTP报文格式
13+
*
14+
* @param request - 解析后的HTTP请求对象
15+
* @returns 格式化的HTTP报文字符串
16+
*
17+
* @example
18+
* toRawHttpRequest({
19+
* method: 'POST',
20+
* url: 'https://example.com/api',
21+
* host: 'example.com',
22+
* path: '/api',
23+
* headers: { 'Content-Type': 'application/json' },
24+
* body: '{"name":"test"}',
25+
* protocol: 'https'
26+
* })
27+
* // => 'POST /api HTTP/1.1\nHost: example.com\nContent-Type: application/json\n\n{"name":"test"}'
28+
*/
29+
export function toRawHttpRequest(request: ParsedHttpRequest): string {
30+
const lines: string[] = []
31+
32+
// 请求行
33+
lines.push(`${request.method} ${request.path} HTTP/1.1`)
34+
35+
// 确保Host头存在
36+
const headers = { ...request.headers }
37+
if (!headers['Host'] && !headers['host']) {
38+
headers['Host'] = request.host
39+
}
40+
41+
// Headers
42+
for (const [name, value] of Object.entries(headers)) {
43+
lines.push(`${name}: ${value}`)
44+
}
45+
46+
// 空行分隔
47+
lines.push('')
48+
49+
// Body
50+
if (request.body) {
51+
lines.push(request.body)
52+
}
53+
54+
return lines.join('\n')
55+
}
56+
57+
/**
58+
* 获取格式的显示名称
59+
*
60+
* @param format - 请求格式类型
61+
* @returns 格式的中文显示名称
62+
*/
63+
export function getFormatDisplayName(format: RequestFormat): string {
64+
return FORMAT_DISPLAY_NAMES[format] || '未知格式'
65+
}
66+
67+
/**
68+
* 从原始HTTP报文中提取请求信息用于提交
69+
*
70+
* 将HTTP报文转换为与后端API兼容的格式
71+
*
72+
* @param rawHttp - 原始HTTP报文字符串
73+
* @returns 提取的请求信息,失败返回null
74+
*/
75+
export function extractRequestFromRawHttp(rawHttp: string): {
76+
url: string
77+
host: string
78+
headers: string[]
79+
body: string
80+
method: string
81+
} | null {
82+
const parsed = parseRawHttp(rawHttp)
83+
if (!parsed) {
84+
return null
85+
}
86+
87+
// 转换headers为数组格式(与后端API兼容)
88+
const headersArray: string[] = []
89+
for (const [name, value] of Object.entries(parsed.headers)) {
90+
headersArray.push(`${name}: ${value}`)
91+
}
92+
93+
return {
94+
url: parsed.url,
95+
host: parsed.host,
96+
headers: headersArray,
97+
body: parsed.body,
98+
method: parsed.method
99+
}
100+
}
101+
102+
/**
103+
* 格式化Headers对象为字符串数组
104+
*/
105+
export function formatHeadersToArray(headers: Record<string, string>): string[] {
106+
return Object.entries(headers).map(([name, value]) => `${name}: ${value}`)
107+
}
108+
109+
/**
110+
* 将字符串数组格式的Headers转换为对象
111+
*/
112+
export function parseHeadersFromArray(headersArray: string[]): Record<string, string> {
113+
const headers: Record<string, string> = {}
114+
115+
for (const header of headersArray) {
116+
const colonIndex = header.indexOf(':')
117+
if (colonIndex > 0) {
118+
const name = header.substring(0, colonIndex).trim()
119+
const value = header.substring(colonIndex + 1).trim()
120+
if (name) {
121+
headers[name] = value
122+
}
123+
}
124+
}
125+
126+
return headers
127+
}

0 commit comments

Comments
 (0)