HowTo: Cross Domain Ajax mit JSONP und ASP.NET
Eigentlich kann man Ajax Requests nur an Adressen senden die unter der gleichen Domain erreichbar sind wie die Seite auf der das Script ausgeführt wird. Der Grund dafür ist die Same Origin Policy in Javascript, diese besagt das der Port, das Protokoll und die Domain gleich sein müssen um Anfragen starten zu dürfen. Das ist zwar sicher, aber leider nicht immer praktisch.
Aber da gibt”™s doch bestimmt einen Trick?
Ja. Es gibt sogar eine ganze Menge verschiedener Möglichkeiten das Problem zu umgehen. Wenn man nach “Cross Domain Ajax” such bekommt man einen bunten Strauß an Lösungen, ich hab bestimmt einen halben Tag gebraucht um mir die verschieden Lösungen anzuschauen. Man könnte einen zum Beispiel einen Proxy einsetzen oder Flash/Silverlight nutzen usw… Für mich war die beste Lösung JSONP zu nutzen.
Was ist JSONP?
JSONP steht für “JSON with padding”. Die Idee ist so simpel wie Clever, man macht sich eine Sicherheitslücke in der Implementation der Same Origin Policy der Browser zu nutze. Man kann zwar keine Requests zu anderen Domains starten aber man kann dynamisch Javascript Dateien von anderen Domains einbinden. Und in diese packt man einfach seine Daten. Das Ganze hat den Nachteil das man Daten nur per GET übergeben kann und kein POST möglich ist. Wer mehr Daten übertragen möchte kann allerdings auf andere Tricks zurückgreifen oder muss sich etwas einschränken.
jQuery macht die Implementation an dieser Stelle wieder sehr einfach und gibt uns die entsprechenden Methoden an die Hand.
Und so sieht”™s aus
Auf dem Client:
$.ajax({
dataType: 'jsonp',
jsonp: 'jsonp_callback',
url: 'http://localhost:56761/TestService.ashx',
success: function (j) {
alert(j.response);
},
});
Der Unterschied zum “normalen” jQuery Request ist eigentlich nur die Zeile “jsonp: ‘jsonp_callback’” diese gibt den GET Parameternamen an in dem jQuery den Namen der Calback Funktion an den Server übermittelt.
Bei jQuery funktioniert das ganze so:
- Es wird ein <script> Tag erzeugt das auf die angegebene Adresse verweist, dabei wird als Parameter wird eine Zufallszahl übergeben(das ist dann der Name der Callbackfunktion).
- Der Server baut als Antwort eine Javascript-Datei zusammen die eine Funktion mit dem Namen der Zufallszahl aufruft und die Daten im JSON Format übergibt.
- Der Browser bindet das Script ein und führt das ganze aus. jQuery übergibt uns jetzt die Daten an das “success” Event.
Und auf dem Server:
string response = context.Request.Params["jsonp_callback"];
response += "({\"response\":\"" + context.Session["RequestCounter"] + " requests startet\"});";
context.Response.Write(response);
Für dieses Beispiel habe ich einen Generic Handler (.ashx) benutzt. Man könnte sicherlich auch einen WCF benutzen.
Die Beispielanwendung besteht aus zwei Projekten, einen Client das “CrossDomainAjax” Projekt und einen Service dem “SourceDomain” Projekt. Um die Demo zu starten müsst ihr mit:
Rechtsklick auf den Projektnamen -> Debug -> Start New Instance
Beide Projekte starten. Danach solltest du dann ein alert mit einer 1 im Browser sehen. Mit diesen Beispiel habe ich noch ausprobiert ob ich auf dem Server dann auch Zugriff auf die Sessesion habe. Und es geht. Bei jeden neu laden der Seite erhöht sich dann der Wert um eins. Gut, das ist jetzt kein spannendes Beispiel aber ich hoffe ihr verzeiht mit das
Den Demo Code gibt”™s hier. Viel Spaß.







Robert S.
11. December 2009
Sehr interessanter Ansatz, muss ich bei Gelegenheit direkt mal ausprobieren. Aber holt man sich damit nich auch irgendwo ne riesen Sicherheitslücke ins Haus?
Oliver Guhr
14. December 2009
Grundsätzlich, nein, also nicht mehr als bei jeden anderen Web Service. Es könnte sein das man deinem Javascript Code per XSS eine andere Web Service Adresse unterschiebt, die Frage ist ob das dem Angreifer was bringt.
Juergen
14. April 2010
Hallo,
danke für die Tipps. Ich war schon am Verzweifeln, weil ich von dieser Sicherheitsmaßnahme nichts wußte. Leider liefert Firefox keinen Fehler, sondern nur Status=0.
Erst Opera zeigte den Fehler in der Fehlerkonsole.
Ich nutze aber lieber einen Proxy. Das erscheint mir sauberer und vor allem zukunftssicherer. Denn wer weiß, wie lange dieses Workaround noch funktionieren wird:
Hier mein Beispiel anhand von google maps
Diese Datei liefert schön valided XML an den AJAX-Ausruf.
Datei: proxy.php
header(‘Content-type: text/xml; charset=”utf-8″‘,true);
readfile(‘http://maps.google.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false‘);
Daniel
24. June 2010
Hallo Jürgen,
natürlich ist der Proxyansatz deutlich eleganter – allerdings gibt es genügend Fälle wo man keine Chance hat einen Proxy einzusetzen oder aber man möchte es den Benutzer möglichst einfach machen wie z.B. bei der Einbindung eines Widget. Als Beispiel mal das Widget von Twitter .. ich glaube nicht das viele Leute es einbinden könnten, wenn man noch serverseitig einen “Proxy” einbinden müsste. Selbst wenn es sich hier um einen simplen Kopiervorgang geht…
Wie gesagt, bei einer eigenen Lösung die man nicht auf andere Websiten verteilen möchte ganz klar Proxy.. ansonsten halt wie hier beschrieben.
Viele Grüße
Daniel