Badgerati / Pode.Web

Web template framework for use with the Pode PowerShell web server
MIT License
189 stars 24 forks source link

Invoke-RestMethod pulling from localhost #616

Open edoutlook opened 1 month ago

edoutlook commented 1 month ago
OS: Windows
Browser: Chrome
Versions:
    Pode: 2.10.1
    Pode.Web: 1.0.0
    PowerShell: 5.1

I've combined three snippets from the tutorial, Basic (the services thing), Button and Route. I was hoping that I could put a button in each row of the table and Use a invoke to, eventually, do an action against a Local route/api. But for some reason, just having the embedded invoke in a button seems to time-out (on the rest get). -I can run the invoke in another ps1 script, same machine, and it works ok. I can pull the 'api' in another chrome tab and that works.

I just can't place it.

Import-Module -Name Pode, Pode.Web

Start-PodeServer {
    Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http
    #Add-PodeEndpoint -Address localhost -Port 8091 -Protocol Http -Name EndpointB

    New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging -Levels @("Error", "Warning")
    New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging

    Add-PodeRoute -Method Get -Path '/api' -ScriptBlock {
    #Add-PodeRoute -Method Get -Path '/api' -EndpointName EndpointB -ScriptBlock {
        # logic
        Write-PodeJsonResponse -Value @{ 'value' = 'pong'; }
    }

    Use-PodeWebTemplates -Title 'testing' -Theme Light

    Add-PodeWebPage -Name 'Services' -Icon 'Settings' -ScriptBlock {
        New-PodeWebCard -Content @(
            New-PodeWebButton -Name 'One' -DataValue 'One' -ScriptBlock {
                $resp = Invoke-RestMethod -Uri 'http://localhost:8091/api' -Method Get
                Show-PodeWebToast -Message "This came from a button, with a data value of $resp"  #'$($WebEvent.Data['Value'])'!"
            }

            New-PodeWebTable -Name 'Services' -ScriptBlock {
                foreach ($svc in (Get-Service | Select-Object -First 3)) {
                    [ordered]@{
                        Name   = $svc.Name
                        Status = "$($svc.Status)"
                        Action   = @(New-PodeWebButton -Name $svc.Name -DataValue $svc.Name -ScriptBlock {
                            Show-PodeWebToast -Message "This came from a button, with a data value of '$($WebEvent.Data['Value'])'!"
                        })
                    }
                }
            }
        )
    }
}
Date: 2024-09-04 19:31:34
Level: Error
ThreadId: 1
Server: DESKTOP-AHVFRTD
Category: InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
Message: Unable to connect to the remote server
StackTrace: at <ScriptBlock>, C:\ps\basic+button+route.ps1: line 22
at Invoke-PodeScriptBlock, C:\Program Files\WindowsPowerShell\Modules\Pode\2.10.1\Public\Utilities.ps1: line 553
at <ScriptBlock>, <No file>: line 6
at Invoke-PodeScriptBlock, C:\Program Files\WindowsPowerShell\Modules\Pode\2.10.1\Public\Utilities.ps1: line 545
at <ScriptBlock>, <No file>: line 124

Date: 2024-09-04 19:31:34
Level: Error
ThreadId: 1
Server: DESKTOP-AHVFRTD
Category: Microsoft.PowerShell.Commands.Utility
Message: Unable to connect to the remote server
StackTrace:    at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetResponse(WebRequest request)
   at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()

Date: 2024-09-04 19:31:34
Level: Error
ThreadId: 1
Server: DESKTOP-AHVFRTD
Category: System
Message: No connection could be made because the target machine actively refused it 127.0.0.1:8091
StackTrace:    at System.Net.Sockets.Socket.InternalEndConnect(IAsyncResult asyncResult)
   at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
   at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)

that test ps1

$output = Invoke-RestMethod -Uri 'http://localhost:8081/api' -Method Get

write-host $output
pause

Here is the output of the ps1 on the same machine

'C:\ps\webtest1.ps1'
@{value=pong}
Press Enter to continue...:

I tried another powershell variant of httpwebrequest, to replace the invoke but it is overly long and didn't behave differently. I read that the Rest and Web Invoke are sort of legacy and the Httpwebrequest is 'newer'?

$url = "http://localhost:8081/api"
$webrequest = [System.Net.HTTPWebRequest]::Create($url);
$webrequest.Method = "GET"
$streamReader = New-Object System.IO.StreamReader(($webrequest.GetResponse()).GetResponseStream())
$output = $streamReader.ReadToEnd()
tmolbergen commented 2 days ago

Out of curiosity, Why do you wish to invoke a webrequest to your own server from the same server? What you would do instead is to call the function and return the output you need directly from the scriptblock.

While it might be possible to do - Most likely using multiple threads would solve your issue (See Start-PodeWebServer? -Threads) The reason why its failing - atleast from my testing is because each scriptblock is a 'blocking' function, which essentially means that your pode web server cant handle any more requests than its already handling, so when you are clicking the button its trying to do another request and ends up locking up since it cant handle any more requests.