关于v$datafile中system表空间的status值始终为system

本文解析了Oracle数据库中V$DATAFILE视图的用途及其包含的数据文件信息,特别是SYSTEM表空间数据文件的独特状态标记。SYSTEM表空间由于其重要性,在V$DATAFILE视图中总是显示为'SYSTEM'状态。
在查询数据文件的文件状态时,可以从v$datafile视图中查询。
v$datafile视图反映了从控制文件中看到的数据文件的状态。

官方对于V$DATAFILE的解释说明是:
This view contains datafile information from the control file.

关于这个视图中的STATUS 列存在五个值,分别是:
1. OFFLINE, 
2.ONLINE, 
3.SYSTEM,
4. RECOVER,
5. SYSOFF (an offline file from the SYSTEM tablespace)

在查询v$datafile视图时,总是能发现system表空间所使用的数据文件的状态是system。
SQL>select file#,name,status from v$datafile
     FILE# NAME                                     STATUS
---------- ---------------------------------------- ---------------------
         1 /oracle/oradata/orcl/system01.dbf        SYSTEM
         2 /oracle/oradata/orcl/undotbs01.dbf       ONLINE
         3 /oracle/oradata/orcl/sysaux01.dbf        ONLINE
         4 /oracle/oradata/orcl/users01.dbf         ONLINE
         5 /oracle/oradata/orcl/perfstat.dbf        ONLINE
         6 /oracle/oradata/orcl/test01.dbf          ONLINE
         7 /oracle/oradata/orcl/qu.dbf              ONLINE
         8 /oracle/oradata/orcl/qu01.dbf            ONLINE
         9 /oracle/oradata/orcl/test2_01.dbf        ONLINE
        10 /oracle/oradata/orcl/qq.dbf              ONLINE

10 rows selected.

对于这一点我觉得应该是system作为oracle数据库最重要的一个表空间,存放了数据字典以及其他的一些定义,所以纵使其他的表空间可以online或者offline,但是对于system表空间来说,是绝对不允许的,它的正常开启也代表了数据库的健康状态。所以只存在system状态。




来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/9390331/viewspace-747153/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/9390331/viewspace-747153/

你看看这个“function Invoke-CurlRequest { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [string]$Url, [string]$Method = "GET", [hashtable]$Headers = @{}, [string]$Body, [string]$ContentType = "application/json", [ValidateSet("Raw", "Object")] [string]$OutputType = "Raw", [switch]$IncludeHeaders, [switch]$FollowRedirect, [int]$MaxRedirects = 10, [int]$Timeout = 0, [string]$OutputFile, [switch]$Insecure ) # 内部辅助函数:提取curl错误信息 function ExtractCurlError([string]$content) { if ($content -match 'curl: \(\d+\) (.*)') { return $matches[1] } return $content } # 内部辅助函数:提取API错误信息 function ExtractApiError($responseData) { $errorKeys = @("error", "message", "detail", "description", "error_message") foreach ($key in $errorKeys) { if ($responseData -and $responseData.PSObject.Properties.Name -contains $key) { return $responseData.$key } } return "Unknown API error" } # 保存原始语言环境 $originalLang = $env:LANG $originalLC_ALL = $env:LC_ALL # 初始化响应对象 $response = [PSCustomObject]@{ Status = $null Content = $null Data = $null ErrorMessage = $null ErrorType = $null Url = $Url Method = $Method StatusCode = $null Headers = $null Latency = $null Size = $null Timestamp = (Get-Date) RawOutput = $null } # 计时器开始 $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() try { # 设置英文环境防止乱码 $env:LANG = 'C' $env:LC_ALL = 'C' # 构建 curl 命令参数 $curlArgs = @( "--url", $Url, # 使用--url参数确保URL完整性 "-X", $Method, "--silent", "--show-error" ) # 添加可选参数 if ($IncludeHeaders) { $curlArgs += "-i" } if ($FollowRedirect) { $curlArgs += "-L" $curlArgs += "--max-redirs" $curlArgs += $MaxRedirects } if ($Timeout -gt 0) { $curlArgs += "--connect-timeout" $curlArgs += [math]::Ceiling($Timeout/2) $curlArgs += "--max-time" $curlArgs += $Timeout } if ($Insecure) { Write-Warning "SSL certificate validation disabled - security risk!" $curlArgs += "--insecure" } # 添加默认User-Agent if (-not $Headers.ContainsKey('User-Agent')) { $Headers['User-Agent'] = "PowerShell-CurlTools/1.0" } # 添加内容类型头 if (-not $Headers.ContainsKey("Content-Type") -and $Body) { $Headers["Content-Type"] = $ContentType } # 添加请求头 foreach ($key in $Headers.Keys) { $headerValue = $Headers[$key] $curlArgs += "-H" $curlArgs += "`"$key`: $headerValue`"" } # 添加请求体 if ($Body) { $curlArgs += "-d" $curlArgs += $Body } Write-Verbose "Executing curl: $($curlArgs -join ' ')" # 特殊处理文件输出 if ($OutputFile) { # 确保输出目录存在 $outputDir = [System.IO.Path]::GetDirectoryName($OutputFile) if (-not [string]::IsNullOrWhiteSpace($outputDir) -and -not (Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir -Force | Out-Null } # 直接保存到文件 $curlArgs += "-o" $curlArgs += $OutputFile # 执行命令 $process = Start-Process curl.exe -ArgumentList $curlArgs -NoNewWindow -PassThru -Wait $curlExitCode = $process.ExitCode # 处理结果 if ($curlExitCode -eq 0 -and (Test-Path $OutputFile)) { $response.Status = "Success" $response.Content = "File saved successfully" $response.Size = (Get-Item $OutputFile).Length $response.StatusCode = 200 } else { $response.Status = "Error" $response.ErrorMessage = "File save failed (exit $curlExitCode)" $response.ErrorType = "FileWriteError" $response.StatusCode = 0 } return $response } # 执行 curl 命令(非文件模式) $output = curl.exe @curlArgs 2>&1 $curlExitCode = $LASTEXITCODE # 处理输出 $rawOutput = if ($null -ne $output) { if ($output -is [array]) { $output -join "`n" } else { $output.ToString() } } else { "" } $response.RawOutput = $rawOutput $response.Latency = $stopwatch.ElapsedMilliseconds # 处理 curl 错误 if ($curlExitCode -ne 0) { $response.Status = "Error" $response.ErrorMessage = ExtractCurlError $rawOutput $response.Content = $rawOutput $response.ErrorType = switch ($curlExitCode) { 6 { "DNSResolutionFailed" } 7 { "ConnectionFailed" } 23 { "FileWriteError" } 28 { "Timeout" } default { "CurlError" } } $response.StatusCode = 0 return $response } # 记录响应大小 $response.Size = $rawOutput.Length # 分离响应头和内容 $headerSection = $null $responseBody = $rawOutput $statusCode = 0 # 增强头部分离逻辑 if ($IncludeHeaders -or $rawOutput -match '^HTTP/') { # 查找头部结束位置 $headerEnd = $rawOutput.IndexOf("`n`n") if ($headerEnd -eq -1) { $headerEnd = $rawOutput.IndexOf("`r`n`r`n") } # 分离头部和主体 if ($headerEnd -gt 0) { $headerSection = $rawOutput.Substring(0, $headerEnd) $responseBody = $rawOutput.Substring($headerEnd + 2) # 解析状态码 if ($headerSection -match 'HTTP/\d+\.\d+\s+(\d{3})') { $statusCode = [int]$matches[1] } # 解析响应头 $response.Headers = @{} $headerLines = $headerSection -split "`r`n|`n" foreach ($line in $headerLines) { if ($line -match '^([^:]+):\s*(.+)') { $response.Headers[$matches[1]] = $matches[2].Trim() } } } } # 设置状态码 $response.StatusCode = $statusCode # 设置响应状态 if ($statusCode -ge 400) { $response.Status = "Error" } elseif ($statusCode -eq 204) { $response.Status = "NoContent" } else { $response.Status = "Success" } # 处理空响应 if ([string]::IsNullOrWhiteSpace($responseBody) -and $statusCode -eq 204) { $response.Content = "" return $response } # 原始输出模式 if ($OutputType -eq "Raw") { $response.Content = $rawOutput return $response } # 对象模式 - 尝试解析JSON $response.Content = $responseBody try { $parsedData = $responseBody | ConvertFrom-Json -ErrorAction Stop # 智能提取嵌套数据 if ($parsedData.PSObject.Properties.Name -contains "json") { $response.Data = $parsedData.json } elseif ($parsedData.PSObject.Properties.Name -contains "data") { try { $response.Data = $parsedData.data | ConvertFrom-Json } catch { $response.Data = $parsedData.data } } else { $response.Data = $parsedData } # 如果是错误响应,提取错误信息 if ($response.Status -eq "Error") { $response.ErrorMessage = ExtractApiError $response.Data } return $response } catch { # 非JSON响应 if ($response.Status -eq "Success") { $response.Status = "NonJsonResponse" } return $response } } catch { $response.Status = "Error" $response.ErrorMessage = $_.Exception.Message $response.Content = $_.Exception.Message return $response } finally { # 恢复原始语言环境 $env:LANG = $originalLang $env:LC_ALL = $originalLC_ALL $stopwatch.Stop() } } # 导出模块函数 Export-ModuleMember -Function Invoke-CurlRequest”跟你的对比一下 “function Invoke-CurlRequest { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [string]$Url, [string]$Method = "GET", [hashtable]$Headers = @{}, [string]$Body, [string]$ContentType = "application/json", [ValidateSet("Raw", "Object")] [string]$OutputType = "Raw", [switch]$IncludeHeaders, [switch]$FollowRedirect, [int]$MaxRedirects = 10, [int]$Timeout = 0, [string]$OutputFile, [switch]$Insecure, # 重试参数 (必须放在param块内) [int]$RetryCount = 0, [int]$RetryInterval = 1, [int[]]$RetryOnStatusCodes = @(408, 429, 500, 502, 503, 504), [switch]$RetryOnTimeout ) # 保存原始语言环境 $originalLang = $env:LANG $originalLC_ALL = $env:LC_ALL # 重试计数器 $attempt = 0 $success = $false $finalResponse = $null # 内部辅助函数:提取curl错误信息 (修复作用域问题) function Script:ExtractCurlError([string]$content) { if ($content -match 'curl: \(\d+\) (.*)') { return $matches[1] } return $content } # 内部辅助函数:提取API错误信息 function Script:ExtractApiError($responseData) { $errorKeys = @("error", "message", "detail", "description", "error_message") foreach ($key in $errorKeys) { if ($null -ne $responseData -and $responseData.PSObject.Properties.Name -contains $key) { return $responseData.$key } } return "Unknown API error" } do { $attempt++ try { # 初始化响应对象 $response = [PSCustomObject]@{ Status = $null Content = $null Data = $null ErrorMessage = $null ErrorType = $null Url = $Url Method = $Method StatusCode = $null Headers = $null Latency = $null Size = $null Timestamp = (Get-Date) RawOutput = $null Attempt = $attempt TotalAttempts = $RetryCount + 1 } $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() # 设置英文环境防止乱码 (修复中文乱码) $env:LANG = 'C' $env:LC_ALL = 'C' # 修复URL空格问题:双重转义 $safeUrl = if ($Url -match '\s') { "`"$($Url -replace '"', '\"')`"" } else { $Url } # 构建curl命令参数 $curlArgs = @( $safeUrl, "-X", $Method, "--silent", "--show-error", "--write-out", "`nHTTP_STATUS:%{http_code}`n" ) # 添加可选参数 if ($IncludeHeaders) { $curlArgs += "-i" } if ($FollowRedirect) { $curlArgs += "-L" $curlArgs += "--max-redirs" $curlArgs += $MaxRedirects } if ($Timeout -gt 0) { $curlArgs += "--connect-timeout" $curlArgs += [math]::Ceiling($Timeout/2) $curlArgs += "--max-time" $curlArgs += $Timeout } if ($Insecure) { Write-Warning "SSL certificate validation disabled - security risk!" $curlArgs += "--insecure" } # 添加默认User-Agent if (-not $Headers.ContainsKey('User-Agent')) { $Headers['User-Agent'] = "PowerShell-CurlTools/1.0" } # 添加内容类型头 if (-not $Headers.ContainsKey("Content-Type") -and $Body) { $Headers["Content-Type"] = $ContentType } # 修复特殊字符请求头问题:使用单引号 foreach ($key in $Headers.Keys) { $headerValue = $Headers[$key] -replace "'", "\'" $curlArgs += "-H" $curlArgs += "'$key: $headerValue'" } # 添加请求体 if ($Body) { $curlArgs += "-d" $curlArgs += $Body } Write-Verbose "[Attempt $attempt/$($RetryCount + 1)] Executing curl: $($curlArgs -join ' ')" # 文件下载处理 if ($OutputFile) { # 确保输出目录存在 (修复权限问题) $outputDir = [System.IO.Path]::GetDirectoryName($OutputFile) if (-not [string]::IsNullOrWhiteSpace($outputDir) -and -not (Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir -Force | Out-Null } # 使用临时文件确保原子写入 $tempFile = [System.IO.Path]::GetTempFileName() $fileArgs = $curlArgs + @("-o", $tempFile) try { $process = Start-Process curl.exe -ArgumentList $fileArgs -NoNewWindow -PassThru -Wait $curlExitCode = $process.ExitCode if ($curlExitCode -eq 0 -and (Test-Path $tempFile)) { Move-Item $tempFile $OutputFile -Force $response.Status = "Success" $response.Size = (Get-Item $OutputFile).Length $response.StatusCode = 200 } else { $response.Status = "Error" $response.ErrorMessage = "File save failed (exit $curlExitCode)" } } finally { if (Test-Path $tempFile) { Remove-Item $tempFile -Force } } $finalResponse = $response $success = $true break } # 执行curl命令 $tempFile = [System.IO.Path]::GetTempFileName() try { $tempArgs = $curlArgs + @("-o", $tempFile) $process = Start-Process curl.exe -ArgumentList $tempArgs -NoNewWindow -PassThru -Wait $curlExitCode = $process.ExitCode if (Test-Path $tempFile) { $rawOutput = Get-Content $tempFile -Raw -Encoding UTF8 $response.Size = (Get-Item $tempFile).Length } } finally { Remove-Item $tempFile -Force } $response.RawOutput = $rawOutput $response.Latency = $stopwatch.ElapsedMilliseconds # 提取HTTP状态码 if ($rawOutput -match 'HTTP_STATUS:(\d{3})') { $response.StatusCode = [int]$matches[1] $rawOutput = $rawOutput -replace 'HTTP_STATUS:\d{3}', '' } # 错误处理 if ($curlExitCode -ne 0) { $response.Status = "Error" $response.ErrorMessage = (Script:ExtractCurlError $rawOutput) $response.ErrorType = switch ($curlExitCode) { 6 { "DNSResolutionFailed" } 7 { "ConnectionFailed" } 23 { "WriteError" } 28 { "Timeout" } default { "CurlError($curlExitCode)" } } # 重试逻辑 if ($attempt -le $RetryCount) { $shouldRetry = $false if ($response.ErrorType -in @("ConnectionFailed", "Timeout", "DNSResolutionFailed")) { $shouldRetry = $true } elseif ($RetryOnTimeout -and $response.ErrorType -eq "Timeout") { $shouldRetry = $true } elseif ($response.StatusCode -in $RetryOnStatusCodes) { $shouldRetry = $true } if ($shouldRetry) { # 指数退避算法 $waitTime = $RetryInterval * [math]::Pow(2, $attempt - 1) $jitter = Get-Random -Minimum 0.1 -Maximum ($waitTime * 0.3) $totalWait = [math]::Ceiling($waitTime + $jitter) Write-Verbose "Retryable error detected. Waiting ${totalWait}s before retry..." Start-Sleep -Seconds $totalWait continue } } $finalResponse = $response $success = $true break } # 响应处理 (简化版) $response.Status = if ($response.StatusCode -ge 400) { "Error" } else { "Success" } $response.Content = $rawOutput # 尝试解析JSON if ($OutputType -eq "Object" -and $rawOutput.Trim().StartsWith('{')) { try { $response.Data = $rawOutput | ConvertFrom-Json } catch { $response.ErrorMessage = "JSON parse error: $_" } } $finalResponse = $response $success = $true } catch { $errorMsg = $_.Exception.Message $finalResponse = [PSCustomObject]@{ Status = "FatalError" ErrorMessage = $errorMsg Attempt = $attempt } if ($attempt -gt $RetryCount) { $success = $true } else { $waitTime = $RetryInterval * [math]::Pow(2, $attempt - 1) Start-Sleep -Seconds $waitTime } } finally { # 恢复原始语言环境 $env:LANG = $originalLang $env:LC_ALL = $originalLC_ALL if ($stopwatch.IsRunning) { $stopwatch.Stop() } } } while ($attempt -le $RetryCount -and -not $success) return $finalResponse } # 导出模块函数 Export-ModuleMember -Function Invoke-CurlRequest ”整合好了 再检查检查 发我完整版哈
最新发布
08-17
<think>我们有两个版本的Invoke-CurlRequest函数,需要将它们整合成一个更完善的版本。主要考虑以下几点: 1. 第一个版本提供了基本的curl封装,但缺少重试机制。 2. 第二个版本添加了重试机制,但我们需要将第一个版本中的一些特性(如头部分离、JSON解析等)融合进去。 3. 第二个版本使用临时文件处理输出,避免了内存问题,同时支持大文件下载。 4. 第二个版本在URL和请求头处理上更加安全(如空格转义、单引号包裹请求头)。 整合思路: - 以第二个版本为基础(因为包含了重试机制和更安全的处理) - 将第一个版本中的响应处理逻辑(头部分离、状态码提取、JSON解析)融合到第二个版本中 - 保留第二个版本中的临时文件处理和重试机制 注意:第一个版本中使用了`--write-out`来获取状态码,第二个版本中也有这个特性,但头部分离逻辑在第一个版本中更详细,我们将采用第一个版本的头部分离逻辑。 具体步骤: 1. 在第二个版本中,执行curl后,我们使用第一个版本的头部分离和状态码提取逻辑。 2. 保留第一个版本中详细的JSON解析和错误提取。 3. 在重试逻辑中,除了网络错误和超时,也根据状态码重试(如5xx错误)。 我们将整合后的函数命名为`Invoke-CurlRequest`,并确保包含所有参数。 下面给出完整代码:</think>### 完整整合版 Invoke-CurlRequest 函数 经过仔细对比和优化,以下是整合两个版本优势的完整解决方案: ```powershell function Invoke-CurlRequest { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [string]$Url, [string]$Method = "GET", [hashtable]$Headers = @{}, [string]$Body, [string]$ContentType = "application/json", [ValidateSet("Raw", "Object")] [string]$OutputType = "Raw", [switch]$IncludeHeaders, [switch]$FollowRedirect, [int]$MaxRedirects = 10, [int]$Timeout = 0, [string]$OutputFile, [switch]$Insecure, # 重试参数 [int]$RetryCount = 0, [int]$RetryInterval = 1, [int[]]$RetryOnStatusCodes = @(408, 429, 500, 502, 503, 504), [switch]$RetryOnTimeout ) # 保存原始语言环境 $originalLang = $env:LANG $originalLC_ALL = $env:LC_ALL # 重试计数器 $attempt = 0 $success = $false $finalResponse = $null # 内部辅助函数:提取curl错误信息 function Script:ExtractCurlError([string]$content) { if ($content -match 'curl: \(\d+\) (.*)') { return $matches[1] } return $content } # 内部辅助函数:提取API错误信息 function Script:ExtractApiError($responseData) { $errorKeys = @("error", "message", "detail", "description", "error_message") foreach ($key in $errorKeys) { if ($null -ne $responseData -and $responseData.PSObject.Properties.Name -contains $key) { $errorValue = $responseData.$key if ($errorValue -is [string]) { return $errorValue } elseif ($errorValue -is [psobject]) { return ($errorValue | Format-List | Out-String).Trim() } } } return "Unknown API error" } # 内部辅助函数:分离响应头和内容 function Script:SeparateHeaders([string]$rawOutput) { $headerSection = $null $responseBody = $rawOutput $statusCode = 0 $headers = @{} # 查找头部结束位置 $endings = @("`r`n`r`n", "`n`n", "`r`r", "`r`n") $headerEnd = $null $endingSize = 0 foreach ($ending in $endings) { $pos = $rawOutput.IndexOf($ending) if ($pos -gt -1) { $headerEnd = $pos $endingSize = $ending.Length break } } # 分离头部和主体 if ($null -ne $headerEnd -and $headerEnd -gt 0) { $headerSection = $rawOutput.Substring(0, $headerEnd) $responseBody = $rawOutput.Substring($headerEnd + $endingSize) # 解析状态码 if ($headerSection -match 'HTTP/\d+\.\d+\s+(\d{3})') { $statusCode = [int]$matches[1] } # 解析响应头 $headerLines = $headerSection -split "`r`n|`n" foreach ($line in $headerLines) { if ($line -match '^([^:]+):\s*(.+)') { $headers[$matches[1]] = $matches[2].Trim() } } } return @{ Headers = $headers Body = $responseBody StatusCode = $statusCode } } do { $attempt++ try { # 初始化响应对象 $response = [PSCustomObject]@{ Status = $null Content = $null Data = $null ErrorMessage = $null ErrorType = $null Url = $Url Method = $Method StatusCode = $null Headers = $null Latency = $null Size = $null Timestamp = (Get-Date) RawOutput = $null Attempt = $attempt TotalAttempts = $RetryCount + 1 } $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() # 设置英文环境防止乱码 $env:LANG = 'C' $env:LC_ALL = 'C' # URL安全处理:双重转义 $safeUrl = if ($Url -match '\s') { "`"$($Url -replace '"', '\"')`"" } else { $Url } # 构建curl命令参数 $curlArgs = @( $safeUrl, "-X", $Method, "--silent", "--show-error", "--write-out", "`nHTTP_STATUS:%{http_code}`n" # 用于提取状态码 ) # 添加可选参数 if ($IncludeHeaders) { $curlArgs += "-i" } if ($FollowRedirect) { $curlArgs += "-L" $curlArgs += "--max-redirs" $curlArgs += $MaxRedirects } if ($Timeout -gt 0) { $curlArgs += "--connect-timeout" $curlArgs += [math]::Ceiling($Timeout/2) $curlArgs += "--max-time" $curlArgs += $Timeout } if ($Insecure) { Write-Warning "SSL certificate validation disabled - security risk!" $curlArgs += "--insecure" } # 添加默认User-Agent if (-not $Headers.ContainsKey('User-Agent')) { $Headers['User-Agent'] = "PowerShell-CurlTools/1.0" } # 添加内容类型头 if (-not $Headers.ContainsKey("Content-Type") -and $Body) { $Headers["Content-Type"] = $ContentType } # 请求头处理:使用单引号包裹 foreach ($key in $Headers.Keys) { $headerValue = $Headers[$key] -replace "'", "\'" $curlArgs += "-H" $curlArgs += "'$key: $headerValue'" } # 添加请求体 if ($Body) { $curlArgs += "-d" $curlArgs += $Body } Write-Verbose "[Attempt $attempt/$($RetryCount + 1)] Executing curl: $($curlArgs -join ' ')" # 文件下载处理 if ($OutputFile) { # 确保输出目录存在 $outputDir = [System.IO.Path]::GetDirectoryName($OutputFile) if (-not [string]::IsNullOrWhiteSpace($outputDir) -and -not (Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir -Force | Out-Null } # 使用临时文件确保原子写入 $tempFile = [System.IO.Path]::GetTempFileName() $fileArgs = $curlArgs + @("-o", $tempFile) try { $process = Start-Process curl.exe -ArgumentList $fileArgs -NoNewWindow -PassThru -Wait $curlExitCode = $process.ExitCode if ($curlExitCode -eq 0 -and (Test-Path $tempFile)) { Move-Item $tempFile $OutputFile -Force $response.Status = "Success" $response.Content = "File saved successfully" $response.Size = (Get-Item $OutputFile).Length $response.StatusCode = 200 } else { $response.Status = "Error" $response.ErrorMessage = "File save failed (exit $curlExitCode)" $response.ErrorType = "FileWriteError" $response.StatusCode = 0 } } finally { if (Test-Path $tempFile) { Remove-Item $tempFile -Force } } $finalResponse = $response $success = $true break } # 非文件模式:使用临时文件处理大响应 $tempFile = [System.IO.Path]::GetTempFileName() try { $tempArgs = $curlArgs + @("-o", $tempFile) $process = Start-Process curl.exe -ArgumentList $tempArgs -NoNewWindow -PassThru -Wait $curlExitCode = $process.ExitCode if (Test-Path $tempFile) { $rawOutput = Get-Content $tempFile -Raw -Encoding UTF8 $response.Size = (Get-Item $tempFile).Length } else { $rawOutput = "" } } finally { if (Test-Path $tempFile) { Remove-Item $tempFile -Force } } $response.RawOutput = $rawOutput $response.Latency = $stopwatch.ElapsedMilliseconds # 提取HTTP状态码 if ($rawOutput -match 'HTTP_STATUS:(\d{3})') { $response.StatusCode = [int]$matches[1] $rawOutput = $rawOutput -replace 'HTTP_STATUS:\d{3}', '' } # 处理curl错误 if ($curlExitCode -ne 0) { $response.Status = "Error" $response.ErrorMessage = (Script:ExtractCurlError $rawOutput) $response.ErrorType = switch ($curlExitCode) { 6 { "DNSResolutionFailed" } 7 { "ConnectionFailed" } 23 { "WriteError" } 28 { "Timeout" } 35 { "SSLConnectError" } default { "CurlError($curlExitCode)" } } # 重试逻辑 if ($attempt -le $RetryCount) { $shouldRetry = $false # 网络错误重试 if ($response.ErrorType -in @("ConnectionFailed", "Timeout", "DNSResolutionFailed", "SSLConnectError")) { $shouldRetry = $true } # 超时重试 elseif ($RetryOnTimeout -and $response.ErrorType -eq "Timeout") { $shouldRetry = $true } # HTTP状态码重试 elseif ($response.StatusCode -in $RetryOnStatusCodes) { $shouldRetry = $true } if ($shouldRetry) { # 指数退避算法 + 随机抖动 $waitTime = $RetryInterval * [math]::Pow(2, $attempt - 1) $jitter = Get-Random -Minimum 0.1 -Maximum ($waitTime * 0.3) $totalWait = [math]::Ceiling($waitTime + $jitter) Write-Verbose "Retryable error detected ($($response.ErrorType)). Waiting ${totalWait}s before retry..." Start-Sleep -Seconds $totalWait continue } } $finalResponse = $response $success = $true break } # 分离响应头和内容 $separated = Script:SeparateHeaders $rawOutput $response.Headers = $separated.Headers $responseBody = $separated.Body # 如果没有显式包含头部但检测到了HTTP响应 if (-not $IncludeHeaders -and $separated.StatusCode -gt 0) { $response.StatusCode = $separated.StatusCode } # 设置响应状态 if ($response.StatusCode -ge 400) { $response.Status = "Error" } elseif ($response.StatusCode -eq 204) { $response.Status = "NoContent" } else { $response.Status = "Success" } # 处理空响应 if ([string]::IsNullOrWhiteSpace($responseBody) -and $response.StatusCode -eq 204) { $response.Content = "" $finalResponse = $response $success = $true break } # 原始输出模式 if ($OutputType -eq "Raw") { $response.Content = $rawOutput $finalResponse = $response $success = $true break } # 对象模式 - 尝试解析JSON $response.Content = $responseBody # 检查内容类型 $contentType = if ($response.Headers -and $response.Headers['Content-Type']) { $response.Headers['Content-Type'].Split(';')[0].Trim() } else { "" } # 仅当内容类型为JSON或看起来像JSON时才尝试解析 $isJson = $contentType -match 'json' -or $responseBody.Trim().StartsWith('{') -or $responseBody.Trim().StartsWith('[') if ($isJson) { try { $parsedData = $responseBody | ConvertFrom-Json -ErrorAction Stop # 智能提取嵌套数据 if ($parsedData.PSObject.Properties.Name -contains "json") { $response.Data = $parsedData.json } elseif ($parsedData.PSObject.Properties.Name -contains "data") { try { $response.Data = $parsedData.data | ConvertFrom-Json } catch { $response.Data = $parsedData.data } } else { $response.Data = $parsedData } # 如果是错误响应,提取错误信息 if ($response.Status -eq "Error") { $response.ErrorMessage = Script:ExtractApiError $response.Data } } catch { # 详细的JSON解析错误处理 $jsonError = $_ $errorPosition = if ($_.Exception -match 'line (\d+), position (\d+)') { "Line $($matches[1]), Position $($matches[2])" } else { "Unknown position" } $response.Status = "JsonParseError" $response.ErrorMessage = "JSON parsing failed: $errorPosition - $($_.Exception.Message)" # 尝试提取错误上下文 $errorSnippet = if ($jsonError.Exception -match 'At line:(\d+)') { $lineNum = [int]$matches[1] $lines = $responseBody -split "`n" $start = [Math]::Max(0, $lineNum - 2) $end = [Math]::Min($lines.Count - 1, $lineNum + 2) $lines[$start..$end] -join "`n" } else { $responseBody.Substring(0, [Math]::Min(200, $responseBody.Length)) } $response.Data = @{ ErrorDetails = $_.Exception.Message ErrorContext = $errorSnippet } } } else { # 非JSON响应 if ($response.Status -eq "Success") { $response.Status = "NonJsonResponse" } # 如果是错误响应,设置错误信息 if ($response.Status -eq "Error") { $response.ErrorMessage = "Non-JSON error response" } } $finalResponse = $response $success = $true } catch { $errorMsg = $_.Exception.Message $finalResponse = [PSCustomObject]@{ Status = "FatalError" ErrorMessage = $errorMsg Attempt = $attempt TotalAttempts = $RetryCount + 1 Url = $Url Method = $Method Timestamp = (Get-Date) } if ($attempt -gt $RetryCount) { $success = $true } else { # 指数退避 $waitTime = $RetryInterval * [math]::Pow(2, $attempt - 1) $jitter = Get-Random -Minimum 0.1 -Maximum ($waitTime * 0.3) $totalWait = [math]::Ceiling($waitTime + $jitter) Write-Verbose "Unexpected exception: $errorMsg. Waiting ${totalWait}s before retry..." Start-Sleep -Seconds $totalWait } } finally { # 恢复原始语言环境 $env:LANG = $originalLang $env:LC_ALL = $originalLC_ALL if ($stopwatch.IsRunning) { $stopwatch.Stop() } } } while ($attempt -le $RetryCount -and -not $success) # 所有重试失败 if (-not $success -and -not $finalResponse) { $finalResponse = [PSCustomObject]@{ Status = "MaxRetryExceeded" ErrorMessage = "Failed after $attempt attempts" Url = $Url Method = $Method StatusCode = 0 Attempt = $attempt TotalAttempts = $RetryCount + 1 Timestamp = (Get-Date) } } return $finalResponse } # 导出模块函数 Export-ModuleMember -Function Invoke-CurlRequest ``` ### 关键优化点说明 1. **URL和请求头安全处理**: - URL空格双重转义:`"`"$($Url -replace '"', '\"')`""` - 请求头单引号包裹:`-H "'$key: $headerValue'"` - 特殊字符转义:`$headerValue -replace "'", "\'"` 2. **大文件处理优化**: - 文件下载:使用临时文件原子写入 - 非文件响应:使用临时文件避免内存溢出 - 精确计算响应大小 3. **响应处理增强**: - 独立函数`SeparateHeaders`处理头部分离 - 支持多种换行符格式(`\r\n\r\n`, `\n\n`, `\r\r`) - 智能JSON检测:基于内容类型和内容前缀 4. **错误处理全面**: - 详细的curl错误分类(DNS、连接、超时、SSL等) - JSON解析错误上下文提取 - 错误响应智能分析 5. **重试机制完善**: - 指数退避算法 + 随机抖动 - 支持多种重试条件(网络错误、超时、HTTP状态码) - 重试计数器在响应对象中可见 6. **编码问题解决**: - 强制使用C语言环境执行curl - 显式指定UTF8编码读取响应 - 恢复原始语言环境设置 ### 使用示例 ```powershell # 带空格的URL请求 $response = Invoke-CurlRequest -Url "https://api.example.com/path with space" -Verbose # 文件下载(自动创建目录) $response = Invoke-CurlRequest -Url "https://example.com/file.zip" -OutputFile "C:\Downloads\New Folder\file.zip" # 带特殊字符的请求头 $headers = @{ "Authorization" = "Bearer token:123" "Custom-Header" = "value;with;special=chars" } $response = Invoke-CurlRequest -Url "https://api.example.com" -Headers $headers # 带重试的API调用 $response = Invoke-CurlRequest -Url "https://api.example.com/data" ` -Method GET ` -RetryCount 3 ` -RetryInterval 2 ` -RetryOnStatusCodes 500, 503 ` -RetryOnTimeout ` -OutputType Object # 处理JSON解析错误 if ($response.Status -eq "JsonParseError") { Write-Host "JSON解析失败: $($response.ErrorMessage)" Write-Host "错误上下文:" Write-Host $response.Data.ErrorContext } ``` ### 性能优化建议 1. **连接复用**: ```powershell # 在函数开头添加 $curlArgs += @("--keepalive-time", "60", "--max-time", "120") ``` 2. **响应压缩支持**: ```powershell # 在添加请求头部分 if (-not $Headers.ContainsKey('Accept-Encoding')) { $Headers['Accept-Encoding'] = 'gzip, deflate, br' } ``` 3. **HTTP/2支持**: ```powershell # 添加参数 $curlArgs += "--http2" ``` 4. **并行下载支持**: ```powershell # 添加分块下载参数 $curlArgs += @("--range", "0-999") # 需要结合多线程实现完整的分块下载 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值