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 panggilan JavaScript XMLHttpRequest (XHR) yang dieksekusi di halaman web berinteraksi dengan resource dari domain non-asal. CORS adalah solusi yang umum diterapkan untuk kebijakan asal yang sama yang diterapkan oleh semua browser. Misalnya, jika Anda membuat 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 memberikan solusi untuk masalah ini dengan mengizinkan server untuk ikut serta jika ingin menyediakan berbagi resource lintas origin.

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 membuat proxy API Apigee yang memanggil API layanan di backend. Ingatlah bahwa Apigee berada di antara klien (dalam hal ini browser) dan API backend (layanan). Karena proxy API dieksekusi di server, bukan di browser, dapat memanggil layanan dengan berhasil. Kemudian, yang perlu Anda lakukan adalah melampirkan header CORS ke respons TargetEndpoint. Selama browser mendukung CORS, header ini memberi sinyal kepada browser bahwa tidak masalah untuk melonggarkan kebijakan asal yang sama, sehingga memungkinkan panggilan API lintas origin berhasil.

Setelah proxy dengan dukungan CORS dibuat, Anda dapat memanggil URL proxy API, bukan layanan backend dalam 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>

Melampirkan kebijakan CORS ke PreFlow permintaan ProxyEndpoint

Melampirkan kebijakan Tambahkan CORS ke proxy API baru

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

  • Saat Anda membuat kebijakan dengan memilih kotak centang Tambahkan header CORS di halaman Keamanan pada wizard Buat Proxy
  • Dengan menambahkannya nanti dari dialog Tambahkan Kebijakan

Saat Anda menambahkan kebijakan CORS dengan mencentang kotak, kebijakan yang disebut Add CORS akan ditambahkan secara otomatis ke sistem dan dilampirkan ke preflow permintaan TargetEndpoint.

Kebijakan Add CORS menambahkan header yang sesuai ke respons. Pada dasarnya, header memberi tahu browser asal mana yang akan berbagi resource-nya, metode mana yang diterimanya, dan sebagainya. Anda dapat membaca lebih lanjut header CORS ini di Rekomendasi W3C untuk 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 melakukan langkah-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 sudah ada:

  1. Jika Anda menggunakan UI Apigee di Konsol Cloud: Pilih Proxy development > API Proxies.

    Jika Anda menggunakan UI Apigee 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 sebelah kiri, klik tombol + di baris Kebijakan.
  5. Pada dialog Buat kebijakan, klik kolom Pilih jenis kebijakan, lalu scroll ke bawah ke Keamanan, lalu pilih CORS.

  6. Masukkan detail kebijakan, lalu klik Buat.

  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. Dalam dialog Add policy step, pilih kebijakan CORS.
  10. Klik Tambahkan untuk melampirkan kebijakan.

Editor Proxy Klasik

Untuk menambahkan kebijakan CORS ke proxy API yang sudah ada:

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

    Tampilan Develop ditampilkan di bawah.

    Tampilan pengembangan di Editor Proxy

  4. Pilih proxy API yang ingin Anda tambahi 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 di bagian atas, yang sesuai dengan Request PreFlow. Tindakan ini akan menampilkan daftar semua kebijakan yang dapat Anda buat, yang dikategorikan.
  8. Pilih CORS dalam kategori Security.
  9. Berikan nama, seperti Add CORS, lalu klik Tambahkan.

Menangani permintaan preflight CORS

Preflight CORS mengacu pada pengiriman permintaan ke server untuk memverifikasi apakah server tersebut mendukung CORS. Respons preflight umum mencakup asal yang akan diterima server untuk 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 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. Saat server yang mendukung CORS menerima permintaan OPTIONS, server akan menampilkan serangkaian header CORS ke klien yang menunjukkan tingkat dukungan CORS-nya. Sebagai hasil dari handshake ini, klien mengetahui apa yang diizinkan untuk diminta dari domain non-origin.

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

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

Mari kita lihat contoh alur, lalu bahas bagian yang menangani permintaan pra-penerbangan:

<?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 utama 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 null, proxy akan segera menampilkan header CORS dalam respons ke klien (melewati 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 yang menambahkan kebijakan CORS Add, yang berisi header CORS, ke alur jika permintaan OPTIONS diterima dan header permintaan Origin dan Access-Control-Request-Method tidak 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>