Menambahkan dukungan CORS ke proxy API

Halaman ini berlaku untuk Apigee dan Apigee hybrid.

Lihat Dokumentasi Apigee Edge.

CORS (Cross-origin resource sharing) adalah mekanisme standar yang memungkinkan JavaScript Panggilan XMLHttpRequest (XHR) yang dijalankan di halaman web untuk berinteraksi dengan resource dari non-asal domain. CORS adalah solusi yang umum diimplementasikan untuk kebijakan origin yang sama yang diterapkan oleh semua browser. Misalnya, jika Anda membuat panggilan XHR ke Twitter API dari kode JavaScript mengeksekusi di browser Anda, panggilan akan gagal. Hal ini karena domain menyalurkan laman untuk browser Anda tidak sama dengan domain yang menyajikan Twitter API. CORS memberikan solusi untuk masalah ini dengan mengizinkan server ikut serta jika ingin menyediakan resource lintas asal berbagi.

Kasus penggunaan umum untuk CORS

Kode JQuery berikut memanggil layanan target fiktif. Jika dieksekusi 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 backend. Perlu diingat bahwa Apigee berada di antara klien (dalam hal ini browser) dan backend. API (layanan). Karena proxy API dieksekusi di server, bukan di browser, proxy dapat memanggil layanan. Lalu, yang perlu Anda lakukan melampirkan header CORS ke respons TargetEndpoint. Selama browser mendukung CORS, header ini memberikan sinyal ke browser bahwa Anda dapat melonggarkan kebijakan asal yang sama, sehingga panggilan API lintas origin agar berhasil.

Setelah proxy dengan dukungan CORS dibuat, Anda dapat memanggil URL proxy API, bukan layanan backend di kode sisi klien Anda. 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>

Penambahan kebijakan CORS ke PreFlow permintaan ProxyEndpoint

Melampirkan kebijakan Tambahkan CORS ke API baru {i>proxy<i}

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

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

Saat Anda menambahkan kebijakan CORS dengan mencentang kotak tersebut, kebijakan yang disebut Add CORS akan otomatis ditambahkan ke sistem dan dilampirkan ke pra-alur permintaan TargetEndpoint.

Kebijakan Tambahkan CORS akan menambahkan header yang sesuai ke respons. Pada dasarnya, {i>header<i} memberi tahu {i>browser<i} mana sumber daya yang akan diberi {i>resource<i}, metode apa yang diterima, dan seterusnya. Anda dapat membaca header CORS ini lebih lanjut di Rekomendasi W3C untuk Cross-Origin Resource Sharing.

Anda harus mengubah kebijakan sebagai berikut:

  • Tambahkan header content-type dan authorization (wajib untuk mendukung autentikasi dasar atau OAuth2) ke Access-Control-Allow-Headers seperti yang ditunjukkan dalam kutipan kode di bawah ini.
  • Untuk autentikasi OAuth2, Anda mungkin perlu mengambil langkah untuk memperbaiki 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 UI Apigee di Konsol Cloud: Pilih Pengembangan proxy > Proxy API.

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

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

  6. Masukkan detail untuk kebijakan tersebut, lalu klik Create.

  7. Di panel sebelah kiri, klik PreFlow di bagian Target Endpoints > default.
  8. Klik tombol + di samping PreFlow di panel Request di kanan bawah Editor Visual.
  9. Pada dialog Add policy step, pilih kebijakan CORS.
  10. 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 > Proxy API 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 tempat Anda ingin menambahkan kebijakan CORS.
  5. Di editor untuk proxy API baru, klik tab Develop:
  6. Di panel Navigator kiri, klik PreFlow di bagian Target Endpoints > default.
  7. Klik tombol +Step atas yang sesuai dengan Request PreFlow. Ini menampilkan daftar kategori yang berisi semua kebijakan yang dapat Anda buat.
  8. Pilih CORS di kategori Keamanan.
  9. Beri nama, seperti Add CORS, lalu klik Add.

Menangani CORS permintaan preflight

Preflight CORS mengacu pada pengiriman permintaan ke server untuk memverifikasi mendukung CORS. Respons preflight umum mencakup origin mana yang akan diterima server 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 menyetujui permintaan lintas origin permintaan dari asal klien, kebijakan lintas asal browser akan diterapkan dan semua permintaan lintas domain yang dibuat dari klien untuk berinteraksi dengan sumber daya yang dihosting di server tersebut akan gagal.

Biasanya, permintaan preflight CORS dibuat dengan metode HTTP OPTIONS. Ketika server yang mendukung CORS menerima permintaan OPTIONS, tindakan ini akan menampilkan serangkaian header CORS ke klien yang menunjukkan tingkat dukungan CORS-nya. Sebagai hasil dari {i>handshake <i}ini, klien tahu apa yang diizinkan untuk meminta dari domain non-origin.

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

Apigee tidak langsung menyertakan solusi preflight CORS, tetapi mungkin saja terapkan, seperti yang dijelaskan dalam bagian ini. Tujuannya adalah agar proxy mengevaluasi OPTIONS dalam alur kondisional. Kemudian, {i>proxy<i} dapat mengirim respons yang sesuai kembali ke dengan klien besar.

Mari kita lihat contoh alur, lalu bahas 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 penting dari ProxyEndpoint ini adalah sebagai berikut:

  • RouteRule dibuat ke target NULL dengan kondisi untuk permintaan OPTIONS. Perlu diketahui bahwa tidak ada TargetEndpoint yang ditentukan. Jika permintaan OPTIONS diterima dan Asal dan {i>Header<i} permintaan {i>Access-Control-Request-Method<i} tidak null, {i>proxy<i} segera mengembalikan CORS sebagai respons terhadap klien (dengan mengabaikan target "backend" default sebenarnya). Untuk mengetahui detail 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 Tambahkan CORS, yang berisi CORS header, ke flow jika permintaan OPTIONS diterima dan Asal serta Header permintaan 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>