AJAX request na vzálený server
- Shampoo
- Člen | 38
Zdravím,
vytvářím html5 bannery, které budou získávat pomocí AJAXu data ze
vzdáleného serveru.
Na serveru běží Nette aplikace.
Zatím jsem to měl vymyšleno tak, že v rámci presenteru vytvořím akci
a ta mi vrátí nějaká data.
Nicméně AJAX má defaultně omezení, že AJAX požadavk musí být
z localhostu.
Zjistili jsme, že když nastavím hlavičku následovně, tak by měl server normálně odpovědět:
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
Je Nette na tohle připraveno? Co musím v Nette udělat?
Díky moc
Adam
- Shampoo
- Člen | 38
Jo a ještě tohle:
Potřebuji aby jsem používal vanillaJS a tedy takto vypadá požadavek:
<script>
var el = document.getElementById('headline').getElementsByTagName('h1')[0];
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
el.innerHTML = xhttp.responseText;
}
else {
el.innerHTML = 'Nějaký default text';
}
}
xhttp.open("GET", "http://mojeDomena/banner", true);
xhttp.send();
</script>
A takto vypadá akce:
public function actionBanner() {
if ($this->getText()) {
$this->sendResponse(new TextResponse($this->getText()));
}
else {
$this->sendResponse(new TextResponse('No text'));
}
}
Jsem aspoň na správné cestě?
- Shampoo
- Člen | 38
Ok, takže jsem rozběhal Request.
XMLHttpRequestu jsem přidal hlavičku, aby byl ajax request detekován.
<script>
var el = document.getElementById('headline').getElementsByTagName('h1')[0];
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
el.innerHTML = xhttp.responseText;
}
else {
el.innerHTML = 'Nějaký default text';
}
}
xhttp.open("GET", "http://mojeDomena/banner", true);
xhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest"); //důležité
xhttp.send();
</script>
public function actionBanner() {
if ($this->isAjax()) {
if ($this->getText()) {
$this->sendResponse(new Nette\Application\Responses\TextResponse($this->getText()));
}
else {
$this->sendResponse(new Nette\Application\Responses\TextResponse('No text'));
}
}
}
Teď ještě ty vzdálené požadavky…
Editoval Shampoo (27. 4. 2016 13:40)
- Shampoo
- Člen | 38
Ok, tak vyřešeno, prostě jsem si v akci přidal k odpovědi potřebné hlavičky.
$origin = $this->getHttpRequest()->getReferer()->scheme . '://' . $this->getHttpRequest()->getReferer()->host;
$response = $this->getHttpResponse();
$response->addHeader('Access-Control-Allow-Origin', $origin);
$response->addHeader('Access-Control-Allow-Methods', 'GET');
$response->addHeader('Access-Control-Allow-Headers', 'X-Requested-With');
if ($this->getText()) {
$this->sendResponse(new Nette\Application\Responses\TextResponse($this->getText());
}
else {
$this->sendResponse(new Nette\Application\Responses\TextResponse('error'));
}
Vše funguje, nicméně by mne zajímalo, jak jinak elegatně získat doménu ze které požadavek přichází, jelikož $_SERVER[‚HTTP_ORIGIN‘] nefunguje…
- iguana007
- Člen | 970
Nedávno jsem to taky řešil. Správně se tomu říká CORS (https://cs.wikipedia.org/wiki/CORS) a dle toho co jsem si nastudoval na netu by to mělo probíhat následovně:
- Při prvním requestu browser pošle OPTIONS request na server, který mu odpoví hlavičkami bez dalšího contentu, jak si už ukázal
- Ihned následuje klasický request, který už odpoví contentem, který se po ajax volání očekává
- Každý další request se už posílá bez toho OPTIONS requestu
Já u těch CORS AJAX akcí vždý volám následující metodu:
private function setCorsHeaders() {
if (in_array($this->getHttpRequest()->getHeader('Origin'), $this->allowedOrigins)) {
$this->getHttpResponse()->setHeader('Access-Control-Allow-Origin', $this->getHttpRequest()->getHeader('Origin'));
$this->getHttpResponse()->setHeader('Access-Control-Allow-Credentials', 'true');
$this->getHttpResponse()->setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
$this->getHttpResponse()->setHeader('Access-Control-Allow-Headers', 'Accept, Overwrite, Destination, Content-Type, Depth, User-Agent, Translate, Range, Content-Range, Timeout, X-Requested-With, If-Modified-Since, Cache-Control, Location');
$this->getHttpResponse()->setHeader('Access-Control-Max-Age', 1728000);
if ($this->getHttpRequest()->getMethod() == 'OPTIONS') {
$this->terminate();
}
}
}
Také je třeba mít na paměti, že XMLHttpRequest nefunguje ve všech verzích IE ;)