Menambahkan dukungan CORS ke proxy API

Halaman ini berlaku untuk Apigee dan Apigee Hybrid.

Baca dokumentasi Apigee Edge.

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 asal 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 karena 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 ikut serta jika ingin menyediakan resource berbagi resource lintas origin.

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 dengan membuat proxy API Apigee yang memanggil API layanan di backend. Ingat bahwa Apigee berada di antara klien (dalam hal ini browser) dan API backend (layanan). Karena proxy API dieksekusi di server, bukan di browser, proxy dapat memanggil layanan. Selanjutnya, Anda hanya perlu menambahkan header CORS ke respons TargetEndpoint. Selama browser mendukung CORS, header ini akan memberi tahu browser bahwa tidak masalah untuk melonggarkan kebijakan origin yang sama, sehingga panggilan API lintas origin dapat 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 CORS ke PreFlow permintaan ProxyEndpoint

Melampirkan kebijakan Add CORS ke proxy API baru

Anda dapat menambahkan dukungan CORS ke proxy API dengan melampirkan kebijakan Add CORS ke proxy API melalui cara berikut:

  • Saat Anda membuat kebijakan dengan mencentang kotak Add CORS headers di halaman Security dari wizard Build a Proxy
  • Dengan menambahkannya nanti dari dialog Tambahkan Kebijakan

Saat Anda menambahkan kebijakan CORS dengan memilih kotak centang, kebijakan bernama Add CORS akan otomatis ditambahkan ke sistem dan dilampirkan ke preflow permintaan TargetEndpoint.

Kebijakan Add CORS menambahkan header yang sesuai ke respons. Pada dasarnya, header memungkinkan browser mengetahui asal yang akan diajak berbagi resource, metode yang diterima, dan seterusnya. Anda dapat membaca selengkapnya tentang header CORS ini di Rekomendasi W3C Cross-Origin Resource Sharing.

Sebaiknya Anda mengubah kebijakan sebagai berikut:

  • Tambahkan header content-type dan authorization (yang diperlukan untuk mendukung autentikasi dasar atau OAuth2) ke header Access-Control-Allow-Headers, seperti ditunjukkan dalam cuplikan kode di bawah.
  • Untuk autentikasi OAuth2, Anda mungkin perlu mengambil langkah untuk memperbaiki perilaku yang tidak sesuai dengan RFC.
<CORS continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <AllowOrigins>{request.header.origin}</AllowOrigins>
    <AllowMethods>GET, PUT, POST, DELETE</AllowMethods>
    <AllowHeaders>origin, x-requested-with, accept, content-type, authorization</AllowHeaders>
    <ExposeHeaders>*</ExposeHeaders>
    <MaxAge>3628800</MaxAge>
    <AllowCredentials>false</AllowCredentials>
    <GeneratePreflightResponse>true</GeneratePreflightResponse>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</CORS>

Menambahkan header CORS ke proxy yang ada

Editor Proxy Baru

Untuk menambahkan kebijakan CORS ke proxy API yang ada:

  1. Jika Anda menggunakan https://console.cloud.google.com/apigee: Pilih Pengembangan proxy > Proxy API.

    Jika Anda menggunakan Apigee UI klasik: Pilih Develop > API Proxies dan di panel Proxies, pilih lingkungan untuk proxy.

  2. Pilih proxy API yang ingin Anda tambahi kebijakan CORS.
  3. Di editor untuk proxy API baru, klik tab Develop.
  4. Di panel kiri, klik tombol + di baris Policies.
  5. Pada dialog Create policy, klik kolom Select policy type, lalu scroll ke bawah ke bagian Security, lalu pilih CORS.

  6. Masukkan detail kebijakan, lalu klik Create.

  7. Di panel sebelah kiri, klik PreFlow di bagian Target Endpoints > default.
  8. Pilih Proxy Endpoints > default > PreFlow di panel sebelah kiri:

    Endpoint target untuk pemilihan PreFlow di Proxy Explorer.

  9. Klik tombol + di samping PreFlow di panel Response di kanan bawah Visual Editor:

    Klik tombol + di samping PreFlow di panel Response.

  10. Pada dialog Add policy step, pilih kebijakan CORS.
  11. Klik Add untuk melampirkan kebijakan.

Editor Proxy Klasik

Untuk menambahkan kebijakan CORS ke proxy API yang ada:

  1. Login ke UI Apigee.
  2. Pilih Develop > API Proxies di menu navigasi sebelah kiri.
  3. Jika Anda melihat tombol Try now, klik tombol tersebut untuk menampilkan tampilan Develop baru.

    Tampilan Develop ditampilkan di bawah ini.

    Mengembangkan tampilan di Proxy Editor

  4. Pilih proxy API yang ingin Anda tambahi kebijakan CORS.
  5. Di editor untuk proxy API baru, klik tab Develop:
  6. Di panel Navigator sebelah kiri, klik PreFlow di bagian Target Endpoints > default.
  7. Klik tombol +Step atas, yang sesuai dengan Request PreFlow. Tindakan ini akan menampilkan daftar semua kebijakan yang dapat Anda buat yang dikategorikan.
  8. Pilih CORS di kategori Security.
  9. Beri nama, seperti Add CORS, lalu klik Add.

Menangani permintaan preflight CORS

Preflight CORS mengacu pada pengiriman permintaan ke server untuk memverifikasi apakah server mendukung CORS. Respons preflight umum mencakup asal server yang akan menerima permintaan CORS, daftar metode HTTP yang didukung untuk permintaan CORS, header yang dapat digunakan sebagai bagian dari permintaan resource, waktu maksimum respons preflight akan di-cache, dan lainnya. Jika layanan tidak menunjukkan dukungan CORS atau tidak ingin menerima permintaan lintas origin dari origin klien, kebijakan lintas origin browser akan diterapkan dan setiap 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 OPTIONS HTTP. Jika server yang mendukung CORS menerima permintaan OPTIONS, server tersebut akan menampilkan sekumpulan header CORS ke klien yang menunjukkan level dukungan CORS-nya. Akibat handshake ini, klien mengetahui apa yang diizinkan untuk meminta dari domain non-origin.

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

Apigee tidak menyertakan solusi preflight CORS siap pakai, tetapi dapat diimplementasikan, seperti yang dijelaskan di bagian ini. Tujuannya adalah agar proxy dapat mengevaluasi permintaan OPTIONS 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>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Request>
            <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 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 yang menambahkan kebijakan Add CORS, yang berisi header CORS, ke alur jika permintaan OPTIONS diterima dan header permintaan Origin dan Access-Control-Request-Method bukan null.
     <Flow name="OptionsPreFlight">
                <Request>
                    <Step>
                        <Name>add-cors</Name>
                    </Step>
                </Request>
                <Response/>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
     </Flow>