Skip to content

Commit d66b3c0

Browse files
committed
取消fileConfig的suffix选项, intervalTime可以为number, log打印提示, 细节修改
1 parent 4341ef9 commit d66b3c0

File tree

4 files changed

+153
-71
lines changed

4 files changed

+153
-71
lines changed

src/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
export { fetch, fetchFile } from './service'
1+
import { fetch, fetchFile } from './service'
2+
3+
const crawler = {
4+
fetch,
5+
fetchFile
6+
}
7+
8+
export { fetch, fetchFile }
9+
10+
export default crawler

src/service.ts

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,46 @@ import fs from 'node:fs'
33

44
import { handleConfig, random, sleep } from './utils'
55

6-
import { IFetchConfig, IFetchFileConfig, IRequestConfig } from './types'
6+
import {
7+
IFetchConfig,
8+
IFetchFileConfig,
9+
IRequest,
10+
IRequestConfig
11+
} from './types'
712

813
function request(config: IRequestConfig) {
9-
return new Promise<Buffer>((resolve, reject) => {
14+
return new Promise<IRequest>((resolve, reject) => {
1015
const data = (config.data = JSON.stringify(config.data ?? ''))
11-
const requestConfig = handleConfig(config)
12-
// console.log('requestConfig: ', requestConfig)
16+
const handleConfigRes = handleConfig(config)
1317

14-
const req = https.request(requestConfig, (res) => {
15-
const content: Buffer[] = []
18+
const req = https.request(handleConfigRes, (res) => {
19+
const container: Buffer[] = []
1620

17-
res.on('data', (chunk) => content.push(chunk))
21+
res.on('data', (chunk) => container.push(chunk))
1822

1923
res.on('end', () => {
20-
resolve(Buffer.concat(content))
24+
const data = Buffer.concat(container)
25+
const resolveRes: IRequest = {
26+
contentType: res.headers['content-type'],
27+
contentLength: res.headers['content-length'],
28+
data
29+
}
30+
resolve(resolveRes)
2131
})
2232
})
2333

34+
req.on('timeout', () => {
35+
console.log(`Timeout Error`)
36+
reject(new Error('Timeout'))
37+
})
38+
2439
req.on('error', (err) => {
25-
console.log('err: ', err.message)
40+
console.log('Error: ', err.message)
2641
reject(err)
2742
})
2843

29-
if (requestConfig.method.toLowerCase() === 'post') {
30-
// console.log('requestConfig data: ', data)
44+
// 其他处理
45+
if (handleConfigRes.method === 'POST') {
3146
req.write(data)
3247
}
3348

@@ -37,27 +52,27 @@ function request(config: IRequestConfig) {
3752

3853
export async function fetch<T = any>(config: IFetchConfig): Promise<T> {
3954
const { requestConifg, intervalTime } = config
40-
let res
41-
42-
async function getValue(req: IRequestConfig) {
43-
const bufferRes = await request(req)
44-
return JSON.parse(bufferRes.toString())
45-
}
4655

56+
let res
4757
if (Array.isArray(requestConifg)) {
4858
res = []
4959

5060
for (const item of requestConifg) {
51-
const value = await getValue(item)
52-
res.push(value)
61+
const requestRes = await request(item)
62+
res.push(JSON.parse(requestRes.data.toString()))
63+
64+
if (typeof intervalTime !== 'undefined') {
65+
const timeout =
66+
typeof intervalTime === 'number'
67+
? intervalTime
68+
: random(intervalTime.max, intervalTime.min)
5369

54-
if (intervalTime) {
55-
const timeout = random(intervalTime.max, intervalTime.min)
5670
await sleep(timeout)
5771
}
5872
}
5973
} else {
60-
res = getValue(requestConifg)
74+
const requestRes = await request(requestConifg)
75+
res = JSON.parse(requestRes.data.toString())
6176
}
6277

6378
return res
@@ -66,29 +81,52 @@ export async function fetch<T = any>(config: IFetchConfig): Promise<T> {
6681
export async function fetchFile(config: IFetchFileConfig) {
6782
const { requestConifg, intervalTime, fileConfig } = config
6883

69-
const isRqeArr = Array.isArray(requestConifg)
70-
const requestConifgArr = isRqeArr ? requestConifg : [requestConifg]
84+
const requestConifgArr = Array.isArray(requestConifg)
85+
? requestConifg
86+
: [requestConifg]
7187

72-
const sum = requestConifgArr.length
88+
const total = requestConifgArr.length
7389
let currentCount = 0
90+
let successCount = 0
91+
92+
await Promise.resolve()
7493

75-
console.log(`开始下载, 总数: ${sum} `)
94+
console.log(`Start downloading, total: ${total} `)
7695

7796
for (const item of requestConifgArr) {
7897
currentCount++
7998

80-
const res = await request(item)
81-
const filename = new Date().getTime() + fileConfig.suffix
82-
const path = fileConfig.storeDir + '/' + filename
99+
const requestRes = await request(item)
83100

84-
fs.createWriteStream(path, 'binary').write(res)
85-
console.log(`当前: ${currentCount}`)
101+
const { contentType, data } = requestRes
102+
const filename = `${new Date().getTime()}.${contentType?.split('/').pop()}`
103+
const path = `${fileConfig.storeDir}/${filename}`
104+
105+
fs.createWriteStream(path, 'binary').write(data, (err) => {
106+
if (err) {
107+
return console.log(
108+
`File save error requested for the ${currentCount}: ${err.message}`
109+
)
110+
}
111+
112+
if (++successCount === total) {
113+
console.log('All files downloaded successfully!')
114+
}
115+
})
116+
117+
if (typeof intervalTime !== 'undefined' && currentCount !== total) {
118+
const timeout =
119+
typeof intervalTime === 'number'
120+
? intervalTime
121+
: random(intervalTime.max, intervalTime.min)
122+
123+
console.log(
124+
`The ${currentCount} request is success, sleep for ${timeout}ms`
125+
)
86126

87-
if (intervalTime && isRqeArr && currentCount !== sum) {
88-
const timeout = random(intervalTime.max, intervalTime.min)
89127
await sleep(timeout)
128+
} else {
129+
console.log(`The ${currentCount} request is success`)
90130
}
91131
}
92-
93-
console.log('下载完成')
94132
}

src/types.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
export interface IAnyObject extends Object {
2+
[key: string | number | symbol]: any
3+
}
4+
5+
export type IMapTypeObject<T extends object, E extends string = ''> = {
6+
[P in keyof T as Exclude<P, E>]: T[P]
7+
}
8+
9+
export type IMapTypeEmptyObject<T extends object, E extends string = ''> = {
10+
[P in keyof T as Exclude<P, E>]?: T[P]
11+
}
12+
113
export type IMethod =
214
| 'get'
315
| 'GET'
@@ -20,30 +32,37 @@ export type IMethod =
2032
| 'unlink'
2133
| 'UNLINK'
2234

23-
export interface IRequestConfig<T = any> {
35+
export interface IRequestConfig {
2436
url: string
2537
method: IMethod
2638
headers?: {
2739
[key: string]: number | string | string[]
2840
}
29-
params?: any
30-
data?: T
41+
params?: IAnyObject
42+
data?: any
3143
timeout?: number
3244
}
3345

34-
export interface IBaseConifg {
46+
export interface IFetchBaseConifg {
3547
requestConifg: IRequestConfig | IRequestConfig[]
36-
intervalTime?: {
37-
max: number
38-
min?: number
39-
}
48+
intervalTime?:
49+
| number
50+
| {
51+
max: number
52+
min?: number
53+
}
4054
}
4155

42-
export type IFetchConfig = IBaseConifg
56+
export type IFetchConfig = IFetchBaseConifg
4357

44-
export interface IFetchFileConfig extends IBaseConifg {
58+
export interface IFetchFileConfig extends IFetchBaseConifg {
4559
fileConfig: {
4660
storeDir: string
47-
suffix: string
4861
}
4962
}
63+
64+
export interface IRequest {
65+
contentType: string | undefined
66+
contentLength: string | undefined
67+
data: Buffer
68+
}

src/utils.ts

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,60 @@
1-
import Url from 'node:url'
2-
import { IRequestConfig } from './types'
1+
import { RequestOptions } from 'https'
32

4-
export function parseParams(params: any): string {
5-
let res = ''
3+
import Url, { URL } from 'node:url'
4+
import { IAnyObject, IMapTypeEmptyObject, IRequestConfig } from './types'
65

7-
if (typeof params === 'object') {
6+
export function parseParams(urlSearch: string, params?: IAnyObject): string {
7+
let res = urlSearch ? `${urlSearch}` : '?'
8+
9+
if (params) {
810
for (const key in params) {
911
const value = params[key]
10-
res += `${key}=${value}`
12+
res += `&${key}=${value}`
1113
}
1214
} else {
13-
res = params
15+
res = urlSearch
1416
}
1517

1618
return res
1719
}
1820

19-
export function handleConfig(rawConfig: IRequestConfig) {
21+
export function parseHeaders(
22+
rawConfig: IRequestConfig,
23+
config: RequestOptions & IMapTypeEmptyObject<URL>
24+
) {
25+
let headers
26+
27+
if (config.method === 'POST' && rawConfig.data) {
28+
headers = {
29+
...rawConfig.headers,
30+
'Content-Type': 'application/json',
31+
'Content-Length': Buffer.byteLength(rawConfig.data)
32+
}
33+
} else {
34+
headers = rawConfig.headers
35+
}
36+
37+
return headers
38+
}
39+
40+
export function handleConfig(
41+
rawConfig: IRequestConfig
42+
): RequestOptions & IMapTypeEmptyObject<URL> {
2043
const { hostname, port, pathname, search } = new Url.URL(rawConfig.url)
21-
const params = search ? search : parseParams(rawConfig.params)
22-
const headers =
23-
rawConfig.method.toLowerCase() === 'post' && rawConfig.data
24-
? {
25-
...rawConfig.headers,
26-
'Content-Type': 'application/json',
27-
'Content-Length': Buffer.byteLength(rawConfig.data)
28-
}
29-
: rawConfig.headers
30-
31-
const requestConfig = {
44+
45+
const config: RequestOptions & IMapTypeEmptyObject<URL> = {
3246
hostname,
3347
port,
3448
path: pathname,
35-
search: params,
36-
method: rawConfig.method,
37-
timeout: rawConfig.timeout,
38-
headers
49+
search: parseParams(search, rawConfig.params),
50+
51+
method: rawConfig.method.toLocaleUpperCase(),
52+
headers: {}
3953
}
4054

41-
return requestConfig
55+
config.headers = parseHeaders(rawConfig, config)
56+
57+
return config
4258
}
4359

4460
export function sleep(timeout: number) {

0 commit comments

Comments
 (0)