Pada artikel sebelumnya telah kita bahas bahwa dengan Javascript, kita tidak dapat melakukan request data ke website lain dikarenakan adanya batasan Same Origin Policy.
Nah pada tutorial kali ini, kita akan membahas segala hal tentang same origin policy ini termasuk bagaimana cara mengatasi batasan yang ada sehingga kita dapat melakukan request data ke website lain menggunakan ajax.
I. Memahami Same Origin Policy
Di dunia intenet terdapat kebijakan bernama “Same Origin Policy” yang mengatur bagaimana script (Javascript) mengakses resource.
Kebijakan ini mengatur bahwa script (Javascript) hanya boleh mengakses resource pada (1) origin (domain) yang sama atau (2) pada origin yang berbeda dengan syarat diijinkan oleh origin tersebut.
1. Bagaimana Implementasi Same Origin Policy
Secara umum implementasi Same Origin Policy adalah sebagai berikut:
- Javascript (melalui browser) melakukan request ke URL yang telah kita tentukan.
- Browser meneruskan request tersebut.
- Alamat yang kita tuju merespon dengan mengirimkan data ke browser kita.
- Browser mengecek HTTP Header pada data tersebut (Pengecekan ini selalu dilakukan browser pada setiap response yang masuk untuk menentukan apa yang harus dilakukan oleh browser).
- Browser mencari apakah pada pada header terdapat properti “Access-Control-Allow-Origin” jika tidak maka data akan diblok. Jika ya, maka akan dicek apakah domain asal Javascript diijinkan untuk mengakses data tersebut, jika ya maka data diteruskan ke Javascript, jika tidak maka data akan diblok.
Untuk lebih jelasnya, perhatikan ilustrasi berikut:
2. Properti Access-Control-Allow-Origin
Seperti yang telah disampaikan sebelumnya bahwa Same Origin Policy ini kuncinya ada pada properti Access-Control-Allow-Origin yang ada di HTTP Header.
Jika Access-Control-Allow-Origin tidak di definisikan, maka dapat dipastikan kita tidak dapat mengakses resource pada website tersebut menggunakan ajax dan umumnya (secara default) properti ini memang tidak didefinisikan.
Untuk mengecek properti ini, silakan buka sebuah website, kemudian lihat bagian HTTP Response headernya, misal saya buka https://medium.com/@steve.yegge/latest?format=json
, HTTP Response yang saya peroleh adalah:
Pada gambar diatas terlihat bahwa tidak ada properti Access-Control-Allow-Origin yang artinya request dari origin berbeda tidak diperbolehkan.
Dengan demikian jika kita mencoba mengakses halaman tersebut menggunakan AJAX, kita akan mendapati error sebagai berikut:
3. Access-Control-Allow-Origin Berupa * (Asterik)
Jika “Access-Control-Allow-Origin” didefinisikan, maka halaman tersebut dapat diakses oleh domain yang berbeda.
Misal saya buka alamat https://cors-proxy.htmldriven.com/?url=https://medium.com/@steve.yegge/latest?format=json
Respon Header yang kita peroleh adalah:
Pada contoh diatas, terlihat properti Access-Control-Allow-Origin bernilai * (asterik) yang artinya semua origin diperbolehkan mengakses halaman tersebut.
Dengan demikian, dengan Javascript AJAX, siapapun termasuk kita dapat mengakses url tersebut.
4. Access-Control-Allow-Origin Berupa URL
Selain asterik, properti Access-Control-Allow-Origin dapat berisi alamat url. Jika berupa url, maka hanya url tersebut yang diperbolehkan untuk mengakses halaman dimaksud.
Alamat URL ini meliputi 1) schema, 2) Domain, dan 3) Port. Perhatikan ilustrasi berikut:
atau dengan default port 8080
Secara default, nomor port adalah 8080, sehingga jika kita tidak mendefinisikan nomor port, berarti port yang digunakan adalah 8080, misal: https://jagowebdev.com:8080 sama juga dengan https://jagowebdev.com
Request dari origin berbeda diperbolehkan asal memiliki kesamaan pada ketiga komponen diatas, misal request dari: https://jagowebdev.com/wp-content/demo/json-pada-javascript/json-medium.php
diperbolehkan karena telah memenuhi syarat schema, domain, dan port yang sama.
Namun, request dari http://info.jagowebdev.com/
atau https://jagowebdev.com/
tidak diperbolehkan karena domain dan schemanya (https) sudah berbeda.
II. Mengatasi Batasan Same Origin Policy
Sebenarnya Same Origin Policy ini tidak bisa diterobos, namun demikian, terdapat beberapa cara yang dapat kita tempuh agar tidak terkena batasan Same Origin Policy, antara lain:
- Menggunakan Proxy (perantara pihak ketiga).
- Menggunakan iframe.
- JSONP.
1. Menggunakan Proxy
Cara pertama yang paling dapat diandalkan adalah menggunakan proxy (perantara) yaitu berupa website pihak ke tiga.
Pada metode ini, kita melakukan request ke web proxy, kemudian web proxy meneruskan request tersebut ke website yang ingin kita tuju, selanjutnya hasil request dari web proxy tersebut kita ambil menggunakan ajax.
Perhatikan ilustrasi berikut:
Nah, agar data pada web proxy tersebut dapat kita ambil menggunakan ajax, maka dapat dipastikan bahwa web proxy tersebut mendefinisikan Access-Control-Allow-Origin (biasanya berupa asterik *) sehingga dapat diakses oleh origin yang berbeda.
a. Proxy Eksternal
Proxy Eksternal disini maksudnya web proxy disediakan oleh pihak ketiga yang artinya kita tidak memiliki kontrol atas web server proxy tersebut.
Diinternet terdapat banyak website proxy yang dapat kita gunakan dengan gratis salah satunya adalah: https://cors-proxy.htmldriven.com/
Sebagai contoh kita ambil data dari medium.com, script yang kita gunakan adalah sebagai berikut:
<script type="text/javascript">
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
obj = JSON.parse(xhr.responseText);
console.log(obj);
}
}
xhr.open('GET', 'https://cors-proxy.htmldriven.com/?url=https://medium.com/@steve.yegge/latest?format=json');
xhr.send();
</script>
b. Proxy Internal: Origin Sama
Proxy internal disini maksudnya adalah web proxy yang kita buat sendiri sehingga kita memiliki kontrol penuh atas web server. Model proxy ini biasanya digunakan untuk kepentinya internal kita sendiri.
Sebagai contoh misal pada jagowebdev.com saya buat file dengan nama proxy-medium-jagowebdev.php
yang berisi kode untuk mengambil data (dengan PHP bukan dengan AJAX) dari medium.com sebagai berikut:
<?php
$data = file_get_contents('https://medium.com/@steve.yegge/latest?format=json');
echo str_replace('])}while(1);</x>', '', $data);
Script tersebut diatas akan menghasilkan data JSON yang siap untuk di gunakan.
Demo: proxy-medium-jagowebdev.php
str_replace('])}while(1);</x>', '', $data)
untuk menghilangkan ])}while(1);</x>
yang ada di depan data JSON. Penggunaan ])}while(1);</x>
di awal data JSON umum digunakan untuk menghindari JSON Hijacking.Selanjutnya saya buat file json-medium-jagowebdev.html
yang berisi script (javascript) yang akan melakukan request ke file proxy-medium-jagowebdev.php
tersebut.
<!DOCTYPE html>
<html>
<head>
<title>JSON Dari medium.com Dengan AJAX dan Proxy Internal</title>
</head>
<body>
<script type="text/javascript">
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
obj = JSON.parse(xhr.responseText);
console.log(obj);
}
}
xhr.open('GET', 'https://jagowebdev.com/wp-content/demo/json-pada-javascript/proxy-medium-jagowebdev.php');
xhr.send();
</script>
</body>
</html>
Demo: json-medium-jagowebdev.html
c. Proxy Internal: Origin berbeda
Jika proxy berada di domain berbeda, maka kita perlu menambahkan pengaturan Access-Control-Allow-Origin pad header.
Misal kita buat file proxy-medium-webdevzoom.php
pada webdevzoom.com, agar file tersebut dapat diakses dari domain https://jagowebdev.com maka kita atur properti Access-Control-Allow-Origin sebagai berikut:
<?php
header('Access-Control-Allow-Origin:https://jagowebdev.com');
$data = file_get_contents('https://medium.com/@steve.yegge/latest?format=json');
echo str_replace('])}while(1);</x>', '', $data);
Pada contoh diatas, Access-Control-Allow-Origin saya beri nilai https://jagowebdev.com yang artinya hanya request dari https://jagowebdev.com yang diperbolehkan.
Selanjutya kita buat file json-medium-external-proxy-webdevzoom.html
dengan script sama seperti script sebelumnya, hanya pada baris 15 kita ubah menjadi:
xhr.open('GET', 'https://webdevzoom.com/wp-content/demo/json-pada-javascript/proxy-medium-webdevzoom.php');
Demo: json-medium-external-proxy-webdevzoom.html
Request diatas tidak error karena halaman proxy-medium-webdevzoom.php
memberitahu browser (melalui HTTP Response header) bahwa domain https://jagowebdev.com diperbolehkan mengakses halaman tersebut.
Menggunakan Library
Script Proxy diatas bentuknya sederhana, hanya untuk menunjukkan bagaimana proxy bekerja. Jika kita ingin membuat proxy sendiri yang komprehensif, kita dapat menggunakan library yang sudah ada seperti pada corsproxy atau php-cors-domain-proxy
2. Menggunakan iframe
Dengan iframe, kita dapat meload data website lain, namun demikian jika kita ingin memparse data tersebut menggunakan javascript, kita tetap berada di batasan Same Origin Policy.
Kenapa?
Karena seperti telah disampaikan diawal bahwa segala sesuatu yang kita akses menggunakan javascript harus mematuhi ketentuan “Same Origin Policy”.
Jadi, jika website yang ada di iframe berasal dari origin yang berbeda dan kita akses iframe tersebut menggunakan javascript, maka kita akan mendapati error sebagai berikut:
Untuk itu jika origin iframe berbeda, sebaiknya kita gunakan proxy atau JSONP (jika website yang kita tuju menyediakan data dengan format JSONP).
Namun demikian pada kondisi tertentu, ketika kita berada pada domain yang sama kita perlu menyediakan data melalui iframe.
Contoh penerapan iframe pada domain yang sama adalah sebagai berikut:
Misal pada jagowebdev.com saya memiliki file iframe.html yang berisi kode HTML sebagai berikut:
<!DOCTYPE HTML>
<html>
<head>
<title>Website</title>
</head>
<body>
<div id="website">Jagowebdev.com</div>
</body>
</html>
Selanjutnya untuk mengakses data pada file tersebut saya buat file parse-iframe.html dengan isi sebagai berikut:
<!DOCTYPE html>
<html>
<head>
<title>Mengambil Data Pada iframe Dengan Javascript</title>
<head>
<body>
<script type="text/javascript">
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.onload = function (e) {
data = iframe.contentDocument || iframe.contentWindow.document;
website = data.getElementById('website').innerHTML;
iframe.parentElement.removeChild(iframe);
alert(website);
};
iframe.src = 'iframe.html';
document.body.appendChild(iframe);
</script>
</body>
</html>
Demo: parse-iframe.html
3. Menggunakan JSONP
Cara terakhir yang dapat kita gunakan adalah menggunakan JSONP (Json dengan Padding). Dengan JSONP tidak ada batasan “Same Origin Policy”
JSONP ini berbentuk data JSON yang berada di dalam pemanggilan fungsi Javascript, misal:
my_function({"website":"Jagowebdev.com"})
Contoh penggunaan JSONP dapat dibaca pada artikel: JSONP Dengan Javascript dan jQuery – Lintas Domain
Meski tidak ada batasan, penggunaan JSON memiliki kelemahan utama yaitu website yang dituju harus menyediakan data dalam bentuk JSONP
dan ternyata.. tidak banyak website yang menyediakan JSONP, jadi gunakan JSONP jika memang memungkinkan untuk menggunakannya.
Pertanyaan selanjutnya, bagaimana jika kita memiliki akses ke web server dan dengan mudan dapat menyediakan data dengan format JSONP?
Pada kondisi demikian, opsi terbaik tetaplah menggunakan Access-Control-Allow-Origin namun dengan tetap membatasi hanya domain tertentu saja yang dapat megakses resource kita.
Karena dengan model seperti itu penulisan script untuk pengambilan data akan lebih mudah fleksibel dibanding menggunakan JSONP.
Lebih lengkap tentang JSONP dapat dibaca di: JSONP Dengan Javascript dan jQuery – Lintas Domain
Demo penggunaan JSONP: JSONP Dari Flickr.com
III. Kesimpulan
Didalam dunia website terdapat kebijakan bernama “Same Origin Policy” yang mengatur bagaimana Javascript mengakses resourse, baik resource pada origin (domain) yang sama maupun pada origin berbeda.
Inti dari kebijakan Same Origin Policy adalah: untuk alasan keamanan, Javascript hanya diperbolehkan mengakses resource pada origin yang sama atau origin yang berbeda jika sudah mendapat ijin dari resoure tersebut.
Untuk mengatasi batasan Same Origin Policy ini, ada beberapa metode yang dapat kita gunakan, metode yang paling handal adalah menggunakan proxy, karena penggunaannya lebih mudah dan fleksibel.
Demikian pembahasan mengenai Same Origin Policy, semoga bermanfaat.
Subscibe Now
Suka dengan artikel di Jagowebdev.com? jangan sampai ketinggalan, segera join ke milis kami untuk update informasi terbaru dari Jagowebdev.com
2 Feedback dari pembaca
Terima kasih atas ilmunya master…
saya mau tanya, bokehkan…
bagaimanakah caranya kalau mau mengatasi batasan cors policy untuk mengakses file playlist m3u8?
Sama sama mas, untuk cors policy, tidak ada solusi,kita harus punya server sendiri dan membolehkan server kita diakses menggunakan ajax