![]() |
Maschinesteuern mit TNetHttpClient
Problembeschreibung Delphi-HKA-Steuerung. 26.02.24
WK Aufgabe: Ein Blockheizkraftwerk soll mittels eines Delphi-Programms gesteuert werden. Erforderlich beim Zugriff ist eine Authentifizierung, bestehend aus Benutzername und Passwort. Das Auslesen von Betriebswerten geschieht, in dem ein Anforderungsstring gesendet wird in der Form
Delphi-Quellcode:
Ein Steuerbefehl muß mit „Post“ ausgeführt werden und hat die Form
Http://IPAdresse:Port/getKey?k=Hka_Mw1.usDrehzahl&_rnd=9619;
Delphi-Quellcode:
mit den Daten: Stromf_Ew.Anforderung_GLT.bAktiv=1
Http://IPAdresse:Port/SetKeys
Mit einer Htm-Seite können beide Befehle erfolgreich ausgeführt werden, wobei der Anforderungstring darin ist <input type="text" name="Stromf_Ew.Anforderung_GLT.bAktiv" value="1"><br> Lösungsversuch: 1. Sockets, scheiden nach meinem Kenntnisstand aus, da kein Authentifizierungs-Methode zur Verfügung steht. 2. mit NetHttpRequest und NetHttpClient. 2.1 Datenabfrage funktioniert. 2.2 Senden eines Steuerbefehls funktioniert bisher nicht. Das Sendeteil hat entsprechend DocWicki die Form:
Delphi-Quellcode:
Dies habe ich programmiert und dabei als ersten Versuch nur AURL und ASource verwendet, mit ASource: SetKeys&Stromf_Ew.Anforderung_GLT.bAktiv=1
function Post(const AURL: string; const ASource: TStrings; const AResponseContent: TStream = nil; const AEncoding: TEncoding = nil; const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;
Die Verwendung von „Overload“ am Ende der Funktion führt zu einem Compilerfehler. Dies erzeugt keinen Compilerfehler und keinen Laufzeitfehler, aber ein TimeOut, der Server antwortet nicht. Läßt man da „=1“ am Ende des Befehls weg Antwortet der Server mit „OK“ führt den Befehl aber nicht aus. Im zweiten Versuch habe ich zusätzlich AHeaders verwendet, da damit der BefehlsString und der Wert „ =1 “ getrennt werden kann. Dies ergibt keinen Compilerfehler, aber eine Zugriffsverletzung Den verwendeten Code gebe ich hier wieder. Man kann entweder nur Stringliste oder zusätzlich AHeaders verwenden. Kann mir eventuell jemand weiterhelfen? Geht dies überhaupt mit NetHttp…?
Delphi-Quellcode:
[EDIT SAGT]
//StromAnfStr1 = 'Stromf_Ew.Anforderung_GLT.bAktiv';
(*** Daten holen, bearbeiten und anzeigen *************************************) procedure THKA02Form.AnfSenden(Sender: TObject); VAR Antwort : IHTTPResponse; URL : String; AHeaders1: TNetHeaders; ValuePair : TNAmeValuePair; AnfString : TStringList; begin if HKAStromAnf then begin (* URL := 'Http://'+URLHKA+':'+PortHKA+'/Setkeys'; AnfString := TStringList.Create; AnfString.Add('/'+StromAnfStr1); AnfString.Add('=1'); try Antwort := NetHttpRequest1.post(URL,AnfString); Antwort := Antwort; *) URL := 'Http://'+URLHKA+':'+PortHKA; ValuePair := TNameValuePair.Create(StromAnfStr1,'1'); AHeaders1 := TNetHeaders.Create(ValuePair); AHeaders1 := AHeaders1; AnfString := TStringList.Create; AnfString.Add('/SetKeys'); //&'+StromAnfStr1 try Antwort := NetHttpRequest1.post(URL,AnfString,@AHeaders1); // Antwort := NetHttpRequest1.post(URL,AnfString); Antwort := Antwort; (**) finally AnfString.Free; end; end else begin SendeStr := 'Http://'+ URLHKA + ':' + PortHKA + '/' + AnforderungStr; NetHTTPRequest1.GET(SendeStr); end; end; Demo Urls "entschärft", Code-Tags gesetzt MfG Christian Seehase [/EDIT SAGT] |
AW: Maschinesteuern mit TNetHttpClient
Guten Morgen,
der Abfragestring "Http://IPAdresse:Port/getKey?k=Hka_Mw1.usDrehzahl&_rnd=9619" schaut doch sehr noch einer Restanfrage aus. Du könntest es dann mit dem TRestClient, TRestRequest und TRestResponse versuchen. Grüße Klaus |
AW: Maschinesteuern mit TNetHttpClient
Wieso wird AHeaders1 als Adresse übergeben?
Der Parameter ist doch bereits als const TNetHeaders deklariert? Abgesehen davon würde eine Adresse ohne Typ im 3.Parameter AEncoding übergeben werden. |
AW: Maschinesteuern mit TNetHttpClient
Die URL müsste so sein:
![]() "Stromf_Ew.Anforderung_GLT.bAktiv=1" gehört in eine Stringlist die mit dem 2. Parameter bei TNetHttpClient.Post übergeben wird. So müsste es eigentlich gehen. |
AW: Maschinesteuern mit TNetHttpClient
Danke Euch für eure Bemühungen. Ich weiß jetzt nicht, wie ich Euch einzeln ansprechen kann. Ich mache es eben pauschal.
Hallo Klaus, danke für den Tip mit TRestClient. Ich werde es nächste Woche ausprobieren. Hallo Blub, AHeaders1 ohne @ führt zu Compilerfehler "Es gibt keine überladene Version von Post, die man mit diesen Parametern aufrufen kann" Hallo Rolf, Probiert habe ich einmal Stingliste[0] := "Stromf_Ew.Anforderung_GLT.bAktiv": Antwort OK, keine Befehlsausdührung. Stingliste[0] := "Stromf_Ew.Anforderung_GLT.bAktiv=1" und Stingliste[0] := "Stromf_Ew.Anforderung_GLT.bAktiv'; Stingliste[1] := "1". Antwort keine, TimeOut. jeweils URL:Port/SetKeys |
AW: Maschinesteuern mit TNetHttpClient
1. Nutze THttpClient aus System.Net.HttpClient.pas
2. Wie folgt sollte das damit ohne Probleme laufen:
Delphi-Quellcode:
Wenn das nicht geht, müsstest du mal die Doku zu deiner Maschinensteuerung genauer studieren. Womöglich braucht es da noch eine Authentifizierung oder sowas.
uses
System.Net.HttpClient; ... var http: THTTPClient; PostData: TStringList; s: String; begin http := THTTPClient.Create; PostData:= TStringList.Create; try PostData.Text := 'Stromf_Ew.Anforderung_GLT.bAktiv=1'; s := http.Post('Http://deinserver: port/getKey', PostData).ContentAsString; // ohne Leerschlag Memo1.Lines.Text := s; finally PostData.Free; http.Free; end; end; |
AW: Maschinesteuern mit TNetHttpClient
Danke Dir Rolf Frei,
ich werde das ausprobieren, wenn ich wieder zu Hause bin. Im Moment bin ich im Krankenhaus, Notfall, Sorry |
AW: Maschinesteuern mit TNetHttpClient
21.03.24
Lieber Rolf Frei, Ich bin wieder zurück, wenisgsten halbwegs. Ich möchte Dir danken für Deine Mühe. Dein Code hat nur halbwegs funktioniert. Er sendet den String ohne „=1“ einwandfrei und läuft dabei auch über die Authentifizierungsprocedur. Mit „=1“ gibt es einen Timeout und die Authentifizierungsprocedur wird auch nicht angefahren. Es sieht so aus, als ob die „=1“ anders behandelt werden muß. Die Dokumentation sagt: Daten senden Für das Senden von Anlagendaten wird die HTTP POST Methode verwendet. Hierbei werden die Parameter nicht über die URL übergeben sondern sind im Body der Nachricht enthalten. Der URL wird hierfür der Befehl /setKeys angehängt. Die Daten sind wie folgt aufgebaut: GewünschterKey=Wert Beispiel – Stromanforderung senden URL: ![]() Daten: Stromf_Ew.Anforderung_GLT.bAktiv=1 Die erfolgreiche Antwort vom Webserver lautet: Stromf_Ew.Anforderung_GLT.bAktiv ok Bei einer einfachen html-Testseite die funktioniert sieht der Body so aus: <body> <p>Dachs-Ansteuerung</p> <form action="http://192.168.178.25:8080/setKeys" method="post"> Strom Anforderung GLT: <input type="text" name="Stromf_Ew.Anforderung_GLT.bAktiv" Value=1><br> <br> <input type="submit" value="Absenden"><br> </form> </body> |
AW: Maschinesteuern mit TNetHttpClient
Mein Beispielcode vom letzen Post geht bei mir 100% korrekt und entspricht genau dem, was deine funktionierende HTML Form macht. Auf meinem Test Webserver bekomme ich das HTTP Feld "Stromf_Ew.Anforderung_GLT.bAktiv" und der Wert "1", wie erwartet als POST Daten. Kann es eventuell sein, dass die Maschine dann eine SSL/TLS Verbindung herzustellen verucht oder sowas, das dann nicht geht? Hast du schon mal im Browser den Entwicklermodus aktiv gehabt (Beim Firefox F12 / Netzwerkanalyse, Chrome ist ähnlich) und geschaut was da genau beim Absenden des Formulars passiert?
EDIT: Mir ist eben noch aufgefallen, dass die Doku von /setKeys redet und ich in meinem Beispielcode /getKey verwende. Das ist dann natürlich falsch. Korrekt wäre es dann so:
Delphi-Quellcode:
uses
System.Net.HttpClient; ... var http: THTTPClient; PostData: TStringList; s: String; begin http := THTTPClient.Create; PostData:= TStringList.Create; try PostData.Text := 'Stromf_Ew.Anforderung_GLT.bAktiv=1'; s := http.Post('Http://192.168.178.25:8080/setKeys', PostData).ContentAsString; // ohne Leerschlag Memo1.Lines.Text := s; finally PostData.Free; http.Free; end; end; |
AW: Maschinesteuern mit TNetHttpClient
Lieber Rolf Frei,
leider komme ich erst jetzt dazu zu antworten. Dein Code ist in Ordnung. Leider führt er nicht zum Ergebnis. Wie früher führt die Anforderung 'Stromf_Ew.Anforderung_GLT.bAktiv=1' zu einem Timeout. Ich habe die gesendeten Daten aufgezeichnet mit einem Echoserver, der auf einem anderen Server installiert war. Die gesendeten Daten waren im wesentlichen gleich wie mit der HTML-Seite. Trotzdem wird mit der HTML-Seite die Stromanforderung ausgeführt, mit der Delphi-Anforderung nicht. Irgendwas muß noch anders sein. Ich habe schon dem Hersteller geschrieben, aber noch keine Antwort bekommen. Wahrscheinlich muß man den Datenverkehr mit einem TSP/IP Monitor/Sniffer analysieren um den Grund zu finden, warum das eine funktionier, das andere nicht. Gruß WunniKunz |
AW: Maschinesteuern mit TNetHttpClient
Zitat: Erforderlich beim Zugriff ist eine Authentifizierung, bestehend aus Benutzername und Passwort.
Wie schickst Du denn die userdaten mit, bzw. wie authentifizierst Du Dich? Grüße Klaus |
AW: Maschinesteuern mit TNetHttpClient
Hallo Klaus,
Die Authentifizierung läuft über den OnAuthEvent von TNetHTTPClient mit AUserName und APasswort. Der Event wird ausgelöst durch Get-Anforderungen und Post-Anforderungen bestehend aus URL:Port, Stromanforderung ohne "=1". Dies entspricht etwa, wie wenn mit dem Browser URL:Port gesendet wird. Da wird dann auch die Authentifizierung angefordert. Probiert habe ich deshalb zuerst die Authentifizierung anzufordern und dann die volle Post-Anforderung zu senden. Hat aber auch nicht geklappt. Probieren will ich noch, zwischen Authentifizierung und Post einen Delay einzubauen, kann ich aber erst später machen. Gruß WunniKunz |
AW: Maschinesteuern mit TNetHttpClient
Probiere die Requests erstmal mit einem API-Test Tool wie z.B. Postman aus, und gucke Dir genau an, was als Antwort zurückkommt.
Vermutlich setzt die Authentifizierung einen Cookie, denn Du dann bei jedem weiteren Request wieder mitschicken musst. Davon mal abgesehen frage ich mich eh immer, was eine Anmeldung bei einem Ding soll, das nur HTTP spricht und nicht HTTPS... Ohne Verschlüsselung kann jeder eine Anmeldung abfangen und ist dann sofort drin. :roll: |
AW: Maschinesteuern mit TNetHttpClient
Hallo,
naja, es kann wirklich nicht schaden das mal mit Wireshark mitzuschneiden. Grüße TurboMagic |
AW: Maschinesteuern mit TNetHttpClient
Ich hab mal den Datenverkehr zwischen Client und Server aufgezeichnet. Bei der Authentifizierung mittels Browser wird die Zeile generiert:
"Authorization: Basic R0xUOjI2MjE3NQ==", die dann bei jedem Get oder Post-Aufruf mitgesendet wird. Ist dies der Cookie? Wie extrahiert man den in Delphi und sendet ihn jeweils mit? Hat jemand da Erfahrung und eventuell einen Beispielcode? Grüße |
AW: Maschinesteuern mit TNetHttpClient
![]() Falls dein user / Passwort geheim bleiben soll, solltest du das base64 oben oder dein Passwort ändern. |
AW: Maschinesteuern mit TNetHttpClient
Zitat:
![]()
Delphi-Quellcode:
Bis bald...
uses
mormot.core.base, mormot.core.data, mormot.core.text, mormot.core.unicode, mormot.lib.curl; const REQUEST_URL: RawUtf8 = 'http://192.168.178.25:8080/setKeys'; var hnd: TCurl; res: TCurlResult; statusCode: Integer; requestData: RawUtf8; responseData: RawByteString; begin if not CurlIsAvailable then Exit; //=> hnd := curl.easy_init; if hnd <> Nil then try curl.easy_setopt(hnd, coWriteFunction, @CurlWriteRawByteString); curl.easy_setopt(hnd, coWriteData, @responseData); // Basic authentication curl.easy_setopt(hnd, coUserName, RawUtf8('USERNAME')); curl.easy_setopt(hnd coPassword, RawUtf8('PASSWORD')); // Post request data requestData := 'Stromf_Ew.Anforderung_GLT.bAktiv=1'; curl.easy_setopt(hnd, coPostFields, Pointer(requestData)); curl.easy_setopt(hnd, coPostFieldSize, Length(requestData)); curl.easy_setopt(hnd, coURL, Pointer(REQUEST_URL)); curl.easy_setopt(hnd, coCustomRequest, RawUtf8('POST')); res := curl.easy_perform(hnd); if res = crOk then begin curl.easy_getinfo(hnd, ciResponseCode, statusCode); case statusCode of 200: ShowMessage(Utf8ToString(RawUtf8(responseData))); // Stromf_Ew.Anforderung_GLT.bAktiv ok else ShowMessage('Should not happen.'); end; end else ShowMessage(Format('Error: %d (%s)', [Ord(res), curl.easy_strerror(res)])); finally curl.easy_cleanup(hnd); end; end; Thomas |
AW: Maschinesteuern mit TNetHttpClient
Das Passwort ist sicher wichtig, viel wichtiger ist mir aber im Moment wie ich den Authentifizierungsstring speichere und bei jedem Get bzw. Post mitschicke.
Weiss hier jemand etwas? Auf verschiedenen Wunsch hier noch die Sende und Empfangsdaten mitgeschrieben mit NirSoft-SmartSniff: Bei Post mit vorheriger Authentifizierung sieht man, daß der Authentifizierungsstring erzeugt, bei Post aber nicht mitgesendet wird. Authentifizierung mit Browser: GET /index.html HTTP/1.1 Host: 192.168.178.25:8080 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate Accept-Language: de,de-DE;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 HTTP/1.1 401 Unauthorized Content-Length: 13 WWW-Authenticate: Basic realm="DachsEthernet" Date: Sun, 14 Apr 2024 18:41:51 GMT ACCESS DENIED GET /index.html HTTP/1.1 Host: 192.168.178.25:8080 Connection: keep-alive Cache-Control: max-age=0 Authorization: Basic R0xUOjI2MjE3NQ== Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate Accept-Language: de,de-DE;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 HTTP/1.1 200 OK Content-Length: 1145 Content-Type: text/html;charset=iso-8859-1 Date: Sun, 14 Apr 2024 18:42:03 GMT Authentifizierung mit Delphi, Methode Get: GET /getKey?k=Hka_Mw1.usDrehzahl&_rnd=9619 HTTP/1.1 Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded; charset=ASCII Accept: text/html Accept-Charset: utf-8 Accept-Encoding: gzip, deflate Accept-Language: de-DE,de User-Agent: Mozilla/5.0 Host: 192.168.178.25:8080 HTTP/1.1 401 Unauthorized Content-Length: 13 WWW-Authenticate: Basic realm="DachsEthernet" Date: Sun, 14 Apr 2024 12:09:33 GMT ACCESS DENIED GET /getKey?k=Hka_Mw1.usDrehzahl&_rnd=9619 HTTP/1.1 Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded; charset=ASCII Accept: text/html Accept-Charset: utf-8 Accept-Encoding: gzip, deflate Accept-Language: de-DE,de User-Agent: Mozilla/5.0 Host: 192.168.178.25:8080 Authorization: Basic R0xUOjI2MjE3NQ== HTTP/1.1 200 OK Content-Length: 22 Cache-Control: max-age=4, must-revalidate Content-Type: text/plain Date: Sun, 14 Apr 2024 12:09:33 GMT Hka_Mw1.usDrehzahl=0 Delphi mit Methode Post mit Authentifizierungsanforderung vor Senden von Post : ================================================== Index : 3 Protocol : TCP Local Address : 10.211.55.3 Remote Address : 192.168.178.25 Local Port : 61815 Remote Port : 8080 Local Host : WUNNIBALDKUC143.localdomain Remote Host : dachs.fritz.box Service Name : Packets : 12 {6 ; 6} Data Size : 1.265 Bytes {952 ; 313} Total Size : 2.081 Bytes {1.192 ; 889} Data Speed : 0.1 KB/Sec Capture Time : 12.04.2024 15:15:32:861 Last Packet Time : 12.04.2024 15:15:44:848 Duration : 00:00:11.987 Local MAC Address : Remote MAC Address: Local IP Country : Remote IP Country : ================================================== GET /getKey?k=Hka_Mw1.usDrehzahl&_rnd=9619 HTTP/1.1 Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded; charset=ASCII Accept: text/html Accept-Charset: utf-8 Accept-Encoding: gzip, deflate Accept-Language: de-DE,de User-Agent: Mozilla/5.0 Host: 192.168.178.25:8080 HTTP/1.1 401 Unauthorized Content-Length: 13 WWW-Authenticate: Basic realm="DachsEthernet" Date: Fri, 12 Apr 2024 13:15:32 GMT ACCESS DENIED GET /getKey?k=Hka_Mw1.usDrehzahl&_rnd=9619 HTTP/1.1 Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded; charset=ASCII Accept: text/html Accept-Charset: utf-8 Accept-Encoding: gzip, deflate Accept-Language: de-DE,de User-Agent: Mozilla/5.0 Host: 192.168.178.25:8080 Authorization: Basic R0xUOjI2MjE3NQ== HTTP/1.1 200 OK Content-Length: 22 Cache-Control: max-age=4, must-revalidate Content-Type: text/plain Date: Fri, 12 Apr 2024 13:15:32 GMT Hka_Mw1.usDrehzahl=0 POST /setKeys HTTP/1.1 Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded; charset=utf-8 Accept: text/html Accept-Charset: utf-8 Accept-Encoding: gzip, deflate Accept-Language: de-DE,de User-Agent: Mozilla/5.0 Content-Length: 34 Host: 192.168.178.25:8080 Stromf_Ew.Anforderung_GLT.bAktiv=1 |
AW: Maschinesteuern mit TNetHttpClient
Zitat:
|
AW: Maschinesteuern mit TNetHttpClient
Zitat:
Delphi-Quellcode:
var http: THTTPClient; begin ... // Diese Zeile vor dem Post einfügen. http.CustomHeaders['Authorization'] := 'Basic ' + TNetEncoding.Base64.Encode('GLT:262175'); // Danach deinen bisherigen Postbefehl aufrufen http.Post ... ... end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:07 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz