HTTPRequest: Auf Ende des Datenempfangs warten

Hier könnt ihr alle Fragen zu SpiderBasic austauschen.
Benutzeravatar
Kurzer
Beiträge: 1614
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von Kurzer »

Moin,

ich hole mir per HTTPRequest() eine JSON kodierte Userliste von einem PHP script.

Das ganze passiert mit folgendem (nicht allein lauffähigen) Codeschnippsel:

Code: Alles auswählen

[...]
Global JsonString.s

Procedure HttpGetEvent(Success, Result$, UserData)
	If Success
		JsonString = Result$
	Else
		Debug "Error"
		JsonString = ""
	EndIf
EndProcedure

Procedure ExtractJSON()
	HTTPRequest(#PB_HTTP_Post, "http://127.0.0.1/test/getusers.php", "getusers=all", @HttpGetEvent())
	
	Debug "Get Users"
	Debug JsonString
[...]
EndProcedure
Die ExtractJSON() Prozedur wird auf Knopfdruck ausgeführt.

Das Problem ist, dass beim ersten Aufruf der String 'JsonString' leer ist. Erst beim zweiten Aufruf der Prozedur läuft alles wie gewünscht.

Ich vermute, dass der HTTPRequest() Aufruf wieder zurückkommt, bevor die Übertragung der Daten abgeschlossen ist. Kann das sein?
Demzufolge ist 'JsonString' noch nicht gefüllt, wenn es per Debug ausgegeben wird.

Liege ich damit richtig oder hat das Verhalten eine andere Ursache?

Kurzer
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2023: 56 Jahre.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von NicTheQuick »

Wieder ich. Hallo. :D Hab immer noch keinen Plan von Spiderbasic, wohl aber von Javascript.
In Javascript ist fast alles Event-gesteuert. Demnach liegst du wohl mit deiner Annahme richtig. Die Funktion HTTPRequest() wartet nicht bis HttpGetEvent() abgearbeitet wurde, sondern kehrt schon vorher zum normalen Programmfluss zurück.

Tatsächlich ist das auch immer so gewollt und trägt zu einer besseren Benutzererfahrung bei. Denn alle Anfragen an den Server sollten asynchron ablaufen. Nichts sollte den Code ins Stocken geraten lassen, vor allem keine schlechte Internetverbindung oder ein langsamer Server. Denn sobald ein Javascript-Code läuft, stockt im Grunde die ganze Seite.

Lösung: Du solltest alles, was du mit dem Rückgabewert des Servers anstellen willst, einfach in HttpGetEvent tun.
Bild
Benutzeravatar
Kurzer
Beiträge: 1614
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von Kurzer »

Danke für die Erklärung, Nic.

Dann werde ich wohl mit Flags arbeiten, die in dem Callback gesetzt werden.
Wenn ich es (zum testen) nun doch seriell haben möchte und auf das Flag warte, welche Art von Warteloop (mit Timeout) sollte ich dann nutzen?

EDIT: Hmm, nee irgendwas passt da nicht.
In folgendem Code warte ich bis der JsonString von der Eventprozedur gefüllt wurde, aber das funktionier so leider nicht.
Muss das so... oder habe ich einen Denkfehler?

Code: Alles auswählen

EnableExplicit

Global JsonString.s

Procedure HttpGetEvent(Success, Result$, UserData)
	If Success
		JsonString = Result$
		Debug "Aus der Eventprozedur: " + Left(JsonString, 10)
	Else
		Debug "Error"
		JsonString = "#"
EndIf
EndProcedure

Procedure ExtractJSON()
	JsonString = ""
	HTTPRequest(#PB_HTTP_Get, #PB_Compiler_Filename, "", @HttpGetEvent())
	
	; Diese While Schleife mal auskommentieren
	While JsonString = ""
		; Hier kann ich leider kein Delay reinsetzen, weil es das nicht gibt.	
	Wend
	
	Debug "----------------------"
  Debug "Aus der ExtractJSONProzedur: " + Left(JsonString, 10)
EndProcedure

OpenWindow(0, 0, 0, 300, 100, "Read file example", #PB_Window_ScreenCentered)
ButtonGadget(0, 10, 10, 280, 30, "Go")
BindGadgetEvent(0, @ExtractJSON())
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2023: 56 Jahre.
Benutzeravatar
Kiffi
Beiträge: 10620
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von Kiffi »

Kurzer hat geschrieben:In folgendem Code warte ich bis der JsonString von der Eventprozedur gefüllt wurde, aber das funktionier so leider nicht.
Muss das so... oder habe ich einen Denkfehler?
ja, denn mit Deiner Schleife blockierst Du den kompletten Programmablauf.
Wikipedia hat geschrieben:Standardmäßig wird ein Skript innerhalb eines Browsers in Form eines einzigen Threads ausgeführt. Warteschleifen oder lange Berechnungen sind daher in JavaScript-Programmen zu vermeiden.
Grüße ... Peter
Hygge
Benutzeravatar
Kurzer
Beiträge: 1614
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von Kurzer »

Okay, also alles eventbasiert programmieren.

Mit PostEvent() klappt es jetzt auch:

Code: Alles auswählen

EnableExplicit

Enumeration #PB_Event_FirstCustomValue
	#JS_Event_UserslistLoaded
EndEnumeration

Global JsonString.s

Procedure HttpGetEvent(Success, Result$, UserData)
	If Success
		JsonString = Result$
		PostEvent(#JS_Event_UserslistLoaded)
	Else
		Debug "Error"
		JsonString = ""
EndIf
EndProcedure

Procedure GetString()
	JsonString = ""
	HTTPRequest(#PB_HTTP_Get, #PB_Compiler_Filename, "", @HttpGetEvent())
EndProcedure

Procedure ShowString()
  Debug "String: " + Left(JsonString, 10)
EndProcedure

OpenWindow(0, 0, 0, 300, 50, "Test", #PB_Window_ScreenCentered)
ButtonGadget(0, 10, 10, 280, 30, "Go")
BindGadgetEvent(0, @GetString())

BindEvent(#JS_Event_UserslistLoaded, @ShowString())
Irgendwie ist es aber doch recht gewöhnungsbedürftig. Ich wollte mir eigentlich ein Modul schreiben für die Funktionen, die die Daten vom Server holen.

Zum Beispiel ein GetUserlist(List Userlist.Users), welche die Daten vom Server lädt und die als Paramater übergebene Liste damit füllt. Aber da die Funktion nicht zwangsläufig wartet bis die Liste geladen ist, muss ich das wohl anders machen.
Das macht das Auslagern von Funktionalitäten in ein Modul etwas schwer. Das Füllen eines ListViews mit der geladenen Userliste soll z.B. in einer separaten Prozedur oder gar einem separaten Modul realisiert werden.

Hmm, ich glaube ich muss da nochmal ne Nacht drüber schlafen. :roll:
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2023: 56 Jahre.
MenschMarkus
Beiträge: 218
Registriert: 30.04.2009 21:21
Computerausstattung: i5-2300 (2.8 Ghz) Win10 -64bit / PB 5.73 LTS

Re: HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von MenschMarkus »

Hi,

dieses Problem stellt sich mir auch gerade. Das mit dem Postevent() muss ich dann auch mal testen.
Zusätzlich stellt sich mir noch die Frage, kann ich Postevent() nur einmal abfragen oder lässt das auch mehrere Reaktionen des Servers zu?

Um mal das obige Beispiel zu nehmen: Es kommt nicht eine Antwort als JSON String zurück, sondern für jeden User eine eigene Antwort !
Geht das so ?
Falls ja, könnte man ja auch dem User einen Bearteitungsfortschritt mit senden damit er sieht dass sich was im Hintergrund tut. Es könnte sonst der Eindruck entstehen, dass sich die App aufgehängt hat.

Ergänzendes Edit:

Sorry, Edit wieder gelöscht. :oops:
Zuletzt geändert von MenschMarkus am 04.08.2020 16:11, insgesamt 2-mal geändert.
Wissen schadet nur dem, der es nicht hat !
Benutzeravatar
mk-soft
Beiträge: 3691
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von mk-soft »

Man kann über einen kleinen Trick auch Strings per PostEvent verschicken.
Wichtig dann wenn mehrere Http Events kommen, bevor die PostEvents verarbeitet sind. Sonst wird der Globale String überschrieben ...

Da muss man eine wenig mit AllocateStructure und FreeStructure arbeiten.

Habs getestet. Was unter Purebasic geht, geht auch unter Spiderbasic

Code: Alles auswählen

EnableExplicit

Enumeration #PB_Event_FirstCustomValue
  #JS_Event_UserslistLoaded
EndEnumeration

Procedure AllocateString(String.s)
  Protected *Mem.String
  *Mem = AllocateStructure(String)
  If *Mem
    *Mem\s = String
  EndIf
  ProcedureReturn *Mem
EndProcedure

Procedure.s FreeString(*Mem.String)
  Protected String.s
  If *Mem
    String = *Mem\s
    FreeStructure(*Mem)
  EndIf
  ProcedureReturn String
EndProcedure

Procedure HttpGetEvent(Success, Result$, UserData)
  If Success
    ; Speicher für den String anfordern und diesen in Parameter Data übergeben
    PostEvent(#JS_Event_UserslistLoaded, 0, 0, 0, AllocateString(Result$))
  Else
    Debug "Error"
    
  EndIf
EndProcedure

Procedure GetString()
  HTTPRequest(#PB_HTTP_Get, #PB_Compiler_Filename, "", @HttpGetEvent())
EndProcedure

Procedure ShowString()
  Protected JsonString.s
  ; String Speicher aus EventData holen und den Speicher wiederfreigeben
  JsonString = FreeString(EventData())
  Debug "String: " + JsonString
EndProcedure

OpenWindow(0, 0, 0, 300, 50, "Test", #PB_Window_ScreenCentered)
ButtonGadget(0, 10, 10, 280, 30, "Go")
BindGadgetEvent(0, @GetString())

BindEvent(#JS_Event_UserslistLoaded, @ShowString())
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
MenschMarkus
Beiträge: 218
Registriert: 30.04.2009 21:21
Computerausstattung: i5-2300 (2.8 Ghz) Win10 -64bit / PB 5.73 LTS

Re: HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von MenschMarkus »

zu meiner Frage oben: wie lange ist denn der Timeout für eine Antwort des Servers?

Soll heißen, wie lange darf die Verzögerung sein, bis ich bei Mehrfachantwort das nächste php echo/print ausgebe?
Oder muss ich tatsächlich erst auf alle Daten im Server warten, dort speichern und das Ergebnis mit einem mal ausgeben?
Wissen schadet nur dem, der es nicht hat !
Benutzeravatar
Kurzer
Beiträge: 1614
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von Kurzer »

Hallo Namensvetter,

wie meinst du das denn genau mit der Mehrfachantwort vom Server?

Ich bin zwar kein Experte, aber ich denke, dass der HTTPRequest-Callback sein Success erst dann liefert, wenn dein sendendes php file beendet worden ist. Ich bin mir auch nicht sicher, ob der Callback mehrfach aufgerufen wird.

Markus

PS: Du kannst dir ein eigenes Protokoll erstellen und dann mehrer HTTPRequest-Anfragen an deinen Server stellen, um eine Große Datenmenge häppchenweise abzuholen.

Da du das PHP Script dann aber mehrmals startest, müsstest du dir serverseitig irgendwie merken, wie viele Datensätze schon gesendet worden sind (oder du gibst Anzahl bereits übertragener Datensätze beim Aufruf des PHP Scripts als Parameter mit). Wenn es sich um eine SQL-Abfrage handelt, kannst du diese dann einfach nochmal ausführen und mit der LIMIT x, y Klausel festlegen welchen Bereich du aus der Ergebnismenge fetchen willst.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2023: 56 Jahre.
MenschMarkus
Beiträge: 218
Registriert: 30.04.2009 21:21
Computerausstattung: i5-2300 (2.8 Ghz) Win10 -64bit / PB 5.73 LTS

Re: HTTPRequest: Auf Ende des Datenempfangs warten

Beitrag von MenschMarkus »

Ich habe es gerade mal getestet. Es ist eigentlich egal wie lange die Abarbeitung von Mehrfachausgaben dauert. Erst wenn das PHP Skript fertig ist und alles geschrieben wurde, wird wohl ein Status 200 gemeldet und dann erst reagiert der SB Callback. Also einzelne Ausgabe der Ergebnisse scheint nicht möglich zu sein, somit auch keine Fortschrittsmitteilung.
Schade eigentlich....
Kurzer hat geschrieben:wie meinst du das denn genau mit der Mehrfachantwort vom Server?
Na ja, ich lade eine CSV Datei auf den Server die dann abgearbeitet wird. Ich erhalte für jede Zeile eine Antwort die ich an die SB app zurück gebe.
Kurzer hat geschrieben:PS: Du kannst dir ein eigenes Protokoll erstellen und dann mehrer HTTPRequest-Anfragen an deinen Server stellen, um eine Große Datenmenge häppchenweise abzuholen.
zu aufwändig...da bin ich zu faul zu :wink:
Lieber schätze ich den Zeitaufwand und lass einen Countdown mit laufen, der zeigt die ungefähre Restzeit an.
Wissen schadet nur dem, der es nicht hat !
Antworten