könnte man (Du ;-)) fhem beibringen, auf einen JSONP-Request zu reagieren und statt einem responseString den Callback zurückzuschicken?
Also, statt so:
http://fhemhost:8083/fhem?cmd=jsonlist&XHR=1
so, wobei die JSONList dann im myJSONPCallback zurückgeschickt wird:
http://fhemhost:8083/fhem?cmd=jsonlist&XHR=1&callback =myJSONPCallback
Dies ist extrem praktisch um flexibler mit den Restriktionen der SOP umzugehen.
Andy
Bitte es mit dem Author des Moduls (Martin Fischer) klaeren, will da erstmal
nicht reinreden.
hm - ist das nicht mehr eine Basis-Funktion, die eigentlich in fhem reingehört? Ich weiß jetzt im Moment leider nicht, wie fhem intern diese Requests abarbeitet. Aber ich dachte fhem schaut sich diese requests immer an:
http://fhemhost:8083/fhem?cmd=list&XHR=1
und könnte somit quasi alles auch als callback zurückschicken
http://fhemhost:8083/fhem?cmd=list&XHR=1&callback=myCallback
-> {result: ...list... }
Gruß
andy
Am 09.01.2012 um 14:23 schrieb Rudolf Koenig:
> On Mon, Jan 09, 2012 at 11:54:05AM +0100, Andy Fuchs wrote:
>> Hallo Rudi,
>>
>> könnte man (Du ;-)) fhem beibringen, auf einen JSONP-Request zu reagieren und
>> statt einem responseString den Callback zurückzuschicken?
>
> Bitte es mit dem Author des Moduls (Martin Fischer) klaeren, will da erstmal
> nicht reinreden.
>
> --
> To unsubscribe from this group, send email to
> fhem-users+...@googlegroups.com
Basis-Funktion ist relativ, ich brauche jsonlist nicht :) Es ist aber Teil des
FHEM Verzeichnisses und damit genauso "Basis-Funktion", wie at, notify und
filelog.
> und k�nnte somit quasi alles auch als callback zur�ckschicken
Sicher, jsonlist waere auch einfach zu aendern, ich meine aber derjenige der es
gebaut hat, soll erstmal dafuer Support uebernehmen.
> http://fhemhost:8083/fhem?cmd=list&XHR=1&callback=myCallback
Wenn auf der Kommandozeile (== telnet) das als "jsonlist callback myCallback"
aufgerufen werden kann (nachdem man das implementiert hatte :), dann waere
daraus auf HTTP:
http://fhemhost:8083/fhem?cmd=list+callback+myCallback&XHR=1
mir geht's nicht um jsonlist (das war nur ein Beispiel), sondern um die Möglichkeit den request an fhem als JSONP-Request zu schicken und damit die SOP zu umgehen, indem fhem das Ergebnis in einen callback wickelt.
http://fhemhost:8083/fhem?cmd=get%20myLog%20&XHR=1&callback=MyCallback
Andy
Am 09.01.2012 um 15:44 schrieb Rudolf Koenig:
>> hm - ist das nicht mehr eine Basis-Funktion, die eigentlich in fhem
>> reingehört?
>
> Basis-Funktion ist relativ, ich brauche jsonlist nicht :) Es ist aber Teil des
> FHEM Verzeichnisses und damit genauso "Basis-Funktion", wie at, notify und
> filelog.
>
>
>> und könnte somit quasi alles auch als callback zurückschicken
>
> Sicher, jsonlist waere auch einfach zu aendern, ich meine aber derjenige der es
> gebaut hat, soll erstmal dafuer Support uebernehmen.
>
>
>> http://fhemhost:8083/fhem?cmd=list&XHR=1&callback=myCallback
>
> Wenn auf der Kommandozeile (== telnet) das als "jsonlist callback myCallback"
> aufgerufen werden kann (nachdem man das implementiert hatte :), dann waere
> daraus auf HTTP:
>
> http://fhemhost:8083/fhem?cmd=list+callback+myCallback&XHR=1
>
Auf der CommandLine braucht man das ja auch nicht, da die Same-Origin-Policy ja eine 'künstliche' Schranke im Browser ist.
Aber:
Wo müsste ich denn das reinschreiben (sofern ich es in Perl hinbekomme), dass fhem mir den callback ausfüllt und zurückschickt?
http://fhemhost:8083/fhem?cmd=list&callback=myCallback
Gehört das nicht eigentlich so irgendwie in 01_FHEMWEB.pm rein?
if($FW_CALLBACK) {
$FW_RETTYPE = "application/json; charset=$FW_encoding";
...
print $callback . '(' . $json . ');';
}
Bin für jeden Hinweis dankbar.
Andy
Doch, dein SOP Argument hat mich ueberzeugt. Ich meine es macht nur im
Zusammenhang mit XHR Sinn, also sollte im "if($FW_XHR) {" Abschnitt sein.
> if($FW_CALLBACK) {
> $FW_RETTYPE = "application/json; charset=$FW_encoding";
Wieso json? eher "text/javascript, wenn es unbeding sein muss.
FHEMWEB hat von jsonlist keine Ahnung, und das ist gut so :)
>> Gehört das nicht eigentlich so irgendwie in 01_FHEMWEB.pm rein?
>
> Doch, dein SOP Argument hat mich ueberzeugt. Ich meine es macht nur im
> Zusammenhang mit XHR Sinn, also sollte im "if($FW_XHR) {" Abschnitt sein.
Freut mich - und das gibt eine Menge mehr Flexibilität für potentielle Frontends.
Kannst Du das auch reinmachen? Ich trau' mich nicht...
>
>> if($FW_CALLBACK) {
>> $FW_RETTYPE = "application/json; charset=$FW_encoding";
>
> Wieso json? eher "text/javascript, wenn es unbeding sein muss.
> FHEMWEB hat von jsonlist keine Ahnung, und das ist gut so :)
Ich bin mir nicht sicher, ob der Browser den returntype überhaupt interessiert, weil ja ein Callback zurückkommt (ich tippe mal auf 'nein'). Muss man mal ausprobieren.
Grüße
andy
Habs eingebaut, aber statt callback habe ich die Variable jsonp genannt. Also:
http://fhemhost:8083/fhem?cmd=jsonlist&jsonp=MyCallback
XHR ist mit jsonp implicit. Eingecheckt und per fhemupdate zur Verfuegung
gestellt. Bitte testen.
vielen Dank für das Einbauen vom JSONP. Es funktioniert schon fast ;-)
Allerdings wird bei dem Request ein STRING zurückgegeben, aber der müsste in JSON zurückkommen:
Der Request ist so: 'http://<meineIP>/fhem?cmd=jsonlist&jsonp=?';
und zurück kommt dann sowas:
jsonp2('{
"ResultSet": "full",
"Results": [
{
"list": "Global",
"devices": [
{
"DEF": "<no definition>",
"NAME": "global",
"NR": "1",
...
"verbose": "3",
"version": "5.2+SVN from 2012-01-07 ($Id: fhem.pl 1177 2012-01-07 09:00:32Z rudolfkoenig $)"
},
"READINGS": []
}
]
},
...
],
"totalResultsReturned": 33
}
');
und ich bekomme: fhem:1SyntaxError: Unexpected EOF
Könntest Du das bitte noch anpassen?
Danke
Andy
Am 11.01.2012 um 12:44 schrieb Rudolf Koenig:
>> Gehört das nicht eigentlich so irgendwie in 01_FHEMWEB.pm rein?
Da bin ich dagegen, sonst kann man nur jsonlist als Argument verwenden. Ein
eval wirst Du wohl auch selber hinkriegen :)
> Der Request ist so: 'http://<meineIP>/fhem?cmd=jsonlist&jsonp=?';
Falsch :) Der Request ist so:
http://<meineIP>/fhem?cmd=jsonlist&jsonp=MyFunc
Wo kommt der ' und ; her?
> und ich bekomme: fhem:1SyntaxError: Unexpected EOF
Kriege ich nicht. Auch bei jsonp=? nicht. Evtl. Proxy?
>> Allerdings wird bei dem Request ein STRING zurückgegeben, aber der müsste in
>> JSON zurückkommen:
>
> Da bin ich dagegen, sonst kann man nur jsonlist als Argument verwenden. Ein
> eval wirst Du wohl auch selber hinkriegen :)
Nein - das geht nicht, da der Fehler bereits auf Browser-Ebene auftritt, d.h. BEVOR ich überhaupt ein eval ausführen kann (das 'jsonp' wird als Callback interpretiert).
Ausserdem kann man dann eben genau nicht nur jsonlist als Argument verwenden, sondern eben alles. Die Lösung ist eigentlich ganz einfach: Statt dem String zurückzugeben, wrappt man diesen in ein JSON, d.h.
statt
'{ x: [a:1]}' //also als String - so wie jetzt
macht man:
{ result: '{ x: [a:1]}'} //JSON
DANN kann man einen eval auf das 'result' machen. Also eval( myReturnedJSON.result)
>> Der Request ist so: 'http://<meineIP>/fhem?cmd=jsonlist&jsonp=?';
>
> Falsch :) Der Request ist so:
> http://<meineIP>/fhem?cmd=jsonlist&jsonp=MyFunc
> Wo kommt der ' und ; her?
das ' hatte ich nur zum markieren der Zeile benutzt und das ? steht für den Callback Namen:
Wenn ich von meinem Server (sagen wir mal Port 80) diesen Request abschicke:
http://<myip>:8083/fhem?cmd=jsonlist&jsonp=MyFunc
dann erhalte ich im Browser folgendes:
XMLHttpRequest cannot load http://<myip>:8083/fhem?cmd=jsonlist&jsonp=MyFunc. Origin http://<myip> is not allowed by Access-Control-Allow-Origin.
Für den Browser sind die unterschiedlichen ports bereits eine Verletzung der SOP.
>> und ich bekomme: fhem:1SyntaxError: Unexpected EOF
>
> Kriege ich nicht. Auch bei jsonp=? nicht. Evtl. Proxy?
Vermutlich, weil Du Deinen Test von <ip:8083> auf <ip:8083> abschickst. Probier's doch mal von einem anderen Port (oder besser noch: anderen Rechner) aus.
Könntest Du das nochmal probieren? Ich hab' echt alles versucht, aber einen String zurück lässt der Browser nicht.
Gruß
Andy
Klar doch, das sollte doch auch der Sinn von jsonP sein.
Zitat http://de.wikipedia.org/wiki/JavaScript_Object_Notation
Im src-Attribut eines <script>-Elements ist es m�glich, beliebige URLs
anzugeben. F�r dieses Attribut greift die Same-Origin-Policy nicht. Es ist
also m�glich, eine URL in einer anderen Domain anzugeben, die beispielsweise
JSON-Daten zur�ck gibt. Dieses Script h�tte aber keinen Effekt.
Um die JSON-Daten auf dem Client verarbeiten zu k�nnen, verpackt der Server
diese als Parameter in eine JavaScript-Funktion, die im Webbrowser bereits
definiert ist. Der Name dieser Funktion wird dem Server �ber einen Query
String der URL mitgeteilt.
<script>
function
MyFunc(arg)
{
var result = eval arg;
...
}
</script>
<script type="text/javascript"
src="http://fhem:8083/fhem?cmd=jsonlist&jsonp=MyFunc">
</script>
Aber vielleicht verstehe ich auch was nicht.
Du hast es nicht ausprobiert, stimmts? ;-)
> Um die JSON-Daten auf dem Client verarbeiten zu können, verpackt der Server
> diese als Parameter in eine JavaScript-Funktion, die im Webbrowser bereits
> definiert ist. Der Name dieser Funktion wird dem Server über einen Query
> String der URL mitgeteilt.
>
> <script>
> function
> MyFunc(arg)
> {
> var result = eval arg;
> ...
> }
> </script>
Der Browser führt das aus, was er zurückbekommt, also im aktuellen falle
MyFunc('foo') {} // geht aber nicht
wohingegen:
MyFunc({'foo':'bar'}) {} // geht
<zitat http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/ >
The way JSONP works is simple, but requires a little bit of server-side cooperation. Basically, the idea is that you let the client decide on a small chunk of arbitrary text to prepend to the JSON document, and you wrap it in parentheses to create a valid JavaScript document (and possibly a valid function call).
The client decides on the arbitrary prepended text by using a query argument named jsonp with the text to prepend. Simple! With an empty jsonp argument, the result document is simply JSON wrapped in parentheses.
</zitat>
Ich habe in fhem mal die single-quotes bei FW_pO "$FW_jsonp('$FW_cmdret');"; entfernt:
FW_pO "$FW_jsonp($FW_cmdret);";
Dann geht alles wie geschnitten Brot (zumindest mit der JSONList). Möchte man das verallgemeinern gibt es meiner Meinung nach 2 Möglichkeiten:
1.) Wenn $FW_cmdret am Anfang ein { und am Ende ein } hat, dann schickt man es einfach wie oben zurück, ansonsten macht man vorn und hinten eine Klammer dran.
2. Man wrappt das $FW_cmdret in ein JSON:
FW_pO "$FW_jsonp({'jsonresult':'$FW_cmdret'});";
Das wiederum dürfte Ärger machen, wenn man die jsonlist zurückschickt, da diese ja dann als String eingebettet würde.
Egal wie: möchte man das Ergebnis nicht nur auf die jsonlist beschränken, muß man drauf achten, dass der Rückgabewert auch ein gültiges JSON ist, oder ihn encoden.
Mir würde die Variante 1 am besten gefallen.
Mein Perl ist leider viel zu schlecht, sonst würde ich Dir das Snippet schicken :)
Grüße
Andy
>
> <script type="text/javascript"
> src="http://fhem:8083/fhem?cmd=jsonlist&jsonp=MyFunc">
> </script>
>
> Aber vielleicht verstehe ich auch was nicht.
>
Stimmts. Es sollte auch:
eval('result='+arg);
heissen. Damit geht es. Ausprobiert :)
Kannst Du das mal mit einem Stückchen HTML und Javascript ausprobieren - und mir sagen was ich machen muß, damit das bei mir auch geht? ;-)
Grüße
andy
Wie das im Wiki vorgeschlagen wurde:
test.html:
=======
<html>
<head>
<title>Test</title>
<script type="text/javascript">
function MyFunc(arg)
{
eval('result='+arg);
alert(result);
}
//window.onload = MyFunc("HellO");
</script>
<script type="text/javascript"
src="http://fhemhost:8083/fhem?cmd=jsonlist&jsonp=MyFunc">
</script>
</head>
<body>
Test1.
</body>
</html>
=======
Aufruf:
http://webserver/test.html
fhemhost != webserver
Firefox:
----------
unterminated string literal
MyFunc('{
fhem?c...=MyFunc (Zeile 1, Spalte 7)
Safari:
---------
MyFunc('{
fhem:1SyntaxError: Unexpected EOF
Google Chrome:
-----------------------
Uncaught SyntaxError: Unexpected token ILLEGAL
:-(
Alles MacOSX latest rev.
Vielleicht hast Du an Deinen Rechnern die Rechte verdreht?
Gruß
Andy
Am 14.01.2012 um 22:44 schrieb Rudolf Koenig:
>> Kannst Du das mal mit einem Stückchen HTML und Javascript ausprobieren - und
>> mir sagen was ich machen muß, damit das bei mir auch geht? ;-)
>
> Wie das im Wiki vorgeschlagen wurde:
>
> test.html:
> =======
> <html>
> <head>
> <title>Test</title>
> <script type="text/javascript">
> function MyFunc(arg)
> {
> eval('result='+arg);
> alert(result);
> }
> //window.onload = MyFunc("HellO");
> </script>
> <script type="text/javascript"
> src="http://fhemhost:8083/fhem?cmd=jsonlist&jsonp=MyFunc">
> </script>
> </head>
> <body>
> Test1.
> </body>
> </html>
> =======
>
> Aufruf:
> http://webserver/test.html
>
> fhemhost != webserver
>
Nichts dergleichen. Die Meldung deutet darauf hin, dass das schliessende '
fehlt, vermutlich hast Du sie bei deinem Experiment vergessen. Es sollte so
ausschauen:
$FW_cmdret =~ s/'/\\'/g;
FW_pO "$FW_jsonp('$FW_cmdret');";
Oder in Deinem fhem.cfg sind Sonderzeichen, die in jsonlist nicht geschuetzt
sind. Kannst Du dein Experiment auch mit einem minimalen fhem.cfg versuchen?
Nein - ich hab' für die Tests die Original fhem verwendet (ohne irgendwelche Modifikationen).
Mit meiner Variante
FW_pO "$FW_jsonp($FW_cmdret);";
tritt das Problem ja nicht auf (zumindest bei der jsonlist).
> Oder in Deinem fhem.cfg sind Sonderzeichen, die in jsonlist nicht geschuetzt
> sind. Kannst Du dein Experiment auch mit einem minimalen fhem.cfg versuchen?
OK - ich hab dasselbe mal (Original-fhem) mit folgender cfg gemacht - ohne Änderung der Ergebnisse. Auf allen Browsern gibt's Exceptions.
attr global modpath /usr/share/fhem
attr global nofork 1
attr global port 7072 global
attr global statefile /var/log/fhem/fhem.save
attr global verbose 3
define CUNO CUL 192.168.x.y:2323 1234
define WEB FHEMWEB 8083 global
Was für einen Browser verwendest Du denn? Und hast Du's mal mit einem anderen versucht?
Vielleicht wäre es doch einfacher das so zu machen, wie ich es vorgeschlagen habe ;-)
Danke für Deine Mühe
Andy
> On 15 Jan., 02:34, Andy Fuchs <tiptro...@online.de> wrote:> Geht nicht
> - auf keinem meiner Browser. Ich erhalte:> > Firefox:> ----------> >
> unterminated string literal
> Da sind "zuviele" Zeilenumbrüche drin. Im Result des jsonp darf kein
> Zeilenumbruch drin sein.
Deshalb ist's ja meiner Ansicht nach besser gleich alles als JSON zurückzugeben.
a) Sparst Du Dir damit das parsen im UI
b) Können da beliebig viele Returns drin sein (weil diese ja nicht als solche interpretiert werden)
c) Funktioniert das ganze dann auch ohne Umschweife mit den gängigen Javascript-Bibliotheken wie jQuery, Prototype, DoJo, etc...
Andy
> Meine "myJSONPCallback" würde dann so
> aussehen und x enthält dann das passende Object/Array. ("eval" is
> "evil", nur nutzen, wenns der Browser nicht unterstützt, z.B. ie<=7)
>
> function myJSONPCallback(s){ var x = JSON.parse(s);
> ...}
>
Deshalb ist's ja meiner Ansicht nach besser gleich alles als JSON zurückzugeben.
a) Sparst Du Dir damit das parsen im UI
b) Können da beliebig viele Returns drin sein (weil diese ja nicht als solche interpretiert werden)
c) Funktioniert das ganze dann auch ohne Umschweife mit den gängigen Javascript-Bibliotheken wie jQuery, Prototype, DoJo, etc...Andy
Ich hab die 01_FHEMWEB.pl nochmal überarbeitet um CORS auch bei aktiviertem basic auth benutzen zu können.Außerdem noch ein Patch für das Eltako FSM61 EnOcean Modul um released als Status zuzulassen.
Ok, OPTIONS ist wieder drin, aber auf OPTIONS antwortet FHEMWEB nicht richtig,
der kapiert nur GET :). Kannst Du es bitte testen, ich wuesste nicht wie.
if($headerOptions[0]) {
print $c "HTTP/1.1 200 OK\r\n",
$FW_headercors,
"Content-Length: 0\r\n\r\n";
$hash->{BUF}="";
return;
exit(1);
};