Menambahkan dukungan CORS ke proxy API

Anda sedang melihat dokumentasi Apigee Edge.
Buka dokumentasi Apigee X.
info

CORS (Cross-origin resource sharing) adalah mekanisme standar yang memungkinkan panggilan XMLHttpRequest (XHR) JavaScript yang dieksekusi di halaman web berinteraksi dengan resource dari domain non-origin. CORS adalah solusi yang umumnya diimplementasikan untuk "kebijakan origin yang sama" yang diterapkan oleh semua browser. Misalnya, jika Anda melakukan panggilan XHR ke Twitter API dari kode JavaScript yang dieksekusi di browser, panggilan akan gagal. Hal ini dikarenakan domain yang menayangkan halaman ke browser Anda tidak sama dengan domain yang menayangkan Twitter API. CORS menyediakan solusi atas masalah ini dengan mengizinkan server untuk "memilih ikut serta" jika ingin menyediakan berbagi resource lintas asal.

Video: Tonton video singkat untuk mempelajari cara mengaktifkan CORS di proxy API.

Kasus penggunaan umum untuk CORS

Kode JQuery berikut memanggil layanan target fiktif. Jika dijalankan dari dalam konteks browser (halaman web), panggilan akan gagal karena kebijakan origin yang sama:

<script>
var url = "http://service.example.com";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This is where we end up!
            }
    });
  });
});
</script>

Salah satu solusi untuk masalah ini adalah membuat proxy Apigee API yang memanggil API layanan di backend. Perlu diingat bahwa Edge berada di antara klien (dalam hal ini browser) dan backend API (layanan). Karena dieksekusi di server, bukan di browser, proxy API berhasil memanggil layanan. Selanjutnya, Anda hanya perlu melampirkan header CORS ke respons TargetEndpoint. Selama browser mendukung CORS, header ini memberikan sinyal ke browser bahwa Anda boleh "melonggarkan" kebijakan originnya yang sama, sehingga panggilan API lintas origin berhasil.

Setelah proxy dengan dukungan CORS dibuat, Anda dapat memanggil URL proxy API, bukan layanan backend dalam kode sisi klien. Contoh:

<script>
var url = "http://myorg-test.apigee.net/v1/example";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This time, we do not end up here!
            }
    });
  });
});
</script>

Melampirkan kebijakan Tambahkan CORS ke proxy API baru

Anda dapat menambahkan dukungan CORS ke proxy API dengan melampirkan kebijakan "Tambahkan CORS" ke proxy API saat membuatnya. Untuk menambahkan kebijakan ini, centang kotak Add CORS headers di halaman Security pada wizard Build a Proxy.

Jika Anda mencentang kotak ini, kebijakan bernama Add CORS akan otomatis ditambahkan ke sistem dan dilampirkan ke preflow respons TargetEndpoint, seperti yang ditunjukkan pada gambar berikut:

Menambahkan kebijakan CORS ke navigator di bagian Kebijakan dan dilampirkan ke preflow respons TargetEndpoint di geser kanan

Kebijakan Tambahkan CORS diimplementasikan sebagai kebijakanAssignMessage yang menambahkan header yang sesuai ke respons. Pada dasarnya, header memberi tahu browser asal yang akan diajak berbagi resource, metode mana yang diterima, dan seterusnya. Anda dapat membaca lebih lanjut tentang header CORS ini di Rekomendasi W3C Cross-Origin Resource Sharing.

Anda harus mengubah kebijakan sebagai berikut:

  • Tambahkan header content-type dan authorization (diperlukan untuk mendukung autentikasi dasar atau OAuth2) ke header Access-Control-Allow-Headers, seperti yang ditunjukkan dalam cuplikan kode di bawah.
  • Untuk autentikasi OAuth2, Anda mungkin perlu mengambil langkah-langkah untuk memperbaiki perilaku yang tidak sesuai dengan RFC.
  • Sebaiknya gunakan <Set> untuk menetapkan header CORS, bukan <Add>, seperti yang ditunjukkan dalam kutipan di bawah. Saat menggunakan <Add>, jika header Access-Control-Allow-Origin sudah ada, Anda akan menerima error berikut:

    The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

    Untuk mengetahui informasi selengkapnya, lihat Error CORS : header berisi beberapa nilai '*, *', tetapi hanya satu yang diizinkan.

<AssignMessage async="false" continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <FaultRules/>
    <Properties/>
    <Set>
        <Headers>
            <Header name="Access-Control-Allow-Origin">{request.header.origin}</Header>
            <Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, content-type, authorization</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>
        </Headers>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

Menambahkan header CORS ke proxy yang ada

Anda harus membuat kebijakan Tetapkan Pesan baru secara manual dan menyalin kode untuk kebijakan Tambahkan CORS yang tercantum di bagian sebelumnya. Kemudian, lampirkan kebijakan ke preset respons TargetEndpoint proxy API. Anda dapat memodifikasi nilai header sesuai kebutuhan. Untuk mengetahui informasi selengkapnya tentang membuat dan melampirkan kebijakan, lihat Apa itu kebijakan?.

Menangani permintaan preflight CORS

Preflight CORS mengacu pada pengiriman permintaan ke server untuk memverifikasi apakah server mendukung CORS. Respons preflight umum mencakup asal tempat server akan menerima permintaan CORS, daftar metode HTTP yang didukung untuk permintaan CORS, header yang dapat digunakan sebagai bagian dari permintaan resource, respons preflight waktu maksimum akan di-cache, dan lainnya. Jika layanan tidak menunjukkan dukungan CORS atau tidak ingin menerima permintaan lintas-asal dari asal klien, kebijakan lintas asal browser akan diterapkan dan semua permintaan lintas domain yang dibuat dari klien untuk berinteraksi dengan resource yang dihosting di server tersebut akan gagal.

Biasanya, permintaan preflight CORS dibuat dengan metode HTTP OPTIONS. Jika server yang mendukung CORS menerima permintaan OPTIONS, server tersebut akan menampilkan serangkaian header CORS ke klien yang menunjukkan level dukungan CORS-nya. Akibat handshake ini, klien mengetahui apa yang diizinkan untuk diminta dari domain non-origin.

Untuk mengetahui informasi selengkapnya tentang preflight, lihat Rekomendasi W3C Cross-Origin Resource Sharing. Selain itu, ada banyak blog dan artikel di CORS yang dapat Anda rujuk.

Apigee tidak selalu menyertakan solusi preflight CORS, tetapi dapat diimplementasikan, seperti dijelaskan di bagian ini. Tujuannya adalah agar proxy dapat mengevaluasi permintaan OPSI dalam alur bersyarat. Selanjutnya, proxy dapat mengirimkan respons yang sesuai kembali ke klien.

Mari kita lihat contoh flow, lalu bahas bagian-bagian yang menangani permintaan preflight:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request/>
            <Response>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Response>
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
        </Flow>
    </Flows>

    <PreFlow name="PreFlow">
        <Request/>
        <Response/>

    </PreFlow>
    <HTTPProxyConnection>
        <BasePath>/v1/cnc</BasePath>
        <VirtualHost>default</VirtualHost>
        <VirtualHost>secure</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
   </RouteRule>
   <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
</ProxyEndpoint>

Bagian-bagian penting dari ProxyEndpoint ini adalah sebagai berikut:

  • RouteRule dibuat ke target NULL dengan kondisi untuk permintaan OPTIONS. Perhatikan bahwa tidak ada TargetEndpoint yang ditentukan. Jika permintaan OPTIONS diterima dan header permintaan Origin dan Access-Control-Request-Method tidak bernilai null, proxy akan segera menampilkan header CORS sebagai respons terhadap klien (dengan mengabaikan target "backend" default yang sebenarnya). Untuk mengetahui detail tentang kondisi alur dan RouteRule, lihat Kondisi dengan variabel alur.

    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    
  • Alur OptionsPreFlight dibuat dan menambahkan kebijakan Add CORS, yang berisi header CORS, ke flow jika permintaan OPTIONS diterima dan header permintaan Origin dan Access-Control-Request-Method tidak null.

     <Flow name="OptionsPreFlight">
                <Request/>
                <Response>
                    <Step>
                        <Name>add-cors</Name>
                    </Step>
                </Response>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
     </Flow>
    

Menggunakan contoh solusi CORS

Contoh solusi CORS, yang diimplementasikan sebagai flow bersama, tersedia di GitHub. Impor paket alur bersama ke lingkungan Anda dan lampirkan menggunakan flow hook atau langsung ke alur proxy API. Untuk mengetahui detailnya, lihat file README CORS-Shared-FLow yang disediakan bersama contoh.