Tutorial: Aplikasi web satu halaman

Peringatan

Pada 30 Oktober 2020, API Bing Search dipindahkan dari layanan Azure AI ke Bing Search Services. Dokumentasi ini disediakan hanya untuk referensi. Untuk dokumentasi terbaru, lihat dokumentasi Bing Search API. Untuk petunjuk tentang cara membuat sumber daya Azure baru untuk pencarian Bing, lihat Membuat sumber daya Bing Search melalui Marketplace Azure.

Bing Entity Search API memungkinkan Anda mencari informasi di Web tentang entitas dan tempat. Anda dapat meminta salah satu jenis hasil, atau keduanya, dalam kueri tertentu. Definisi tempat dan entitas disediakan di bawah ini.

Hasil Deskripsi
Entitas Orang-orang terkenal, tempat, dan hal-hal yang Anda temukan dengan nama
Tempat Restoran, hotel, dan bisnis lokal lainnya yang Anda temukan berdasarkan nama atau berdasarkan jenisnya (Restoran Italia)

Dalam tutorial ini, kita membangun aplikasi Web satu halaman yang menggunakan Bing Entity Search API untuk menampilkan hasil pencarian di halaman. Aplikasi ini mencakup komponen HTML, CSS, dan JavaScript.

API memungkinkan Anda memprioritaskan hasil berdasarkan lokasi. Di aplikasi ponsel, Anda dapat meminta lokasinya sendiri kepada perangkat. Di apl Web, Anda dapat menggunakan fungsi getPosition() tersebut. Namun, panggilan ini hanya berfungsi dalam konteks yang aman, dan mungkin tidak menyediakan lokasi yang tepat. Selain itu, pengguna mungkin ingin mencari entitas di dekat lokasi selain entitas mereka sendiri.

Oleh karena itu, aplikasi kami meminta layanan Bing Maps untuk mendapatkan garis lintang dan bujur dari lokasi yang dimasukkan pengguna. Pengguna kemudian dapat memasukkan nama tengara ("Space Needle") atau alamat penuh atau parsial ("New York City"), dan Bing Maps API menyediakan koordinat.

Catatan

Judul JSON dan HTTP di bagian bawah halaman memperlihatkan respons JSON dan informasi permintaan HTTP saat diklik. Detail ini dapat berguna saat menjelajahi layanan.

Aplikasi tutorial mengilustrasikan cara:

  • Melakukan panggilan API Pencarian Entitas Bing di JavaScript
  • Melakukan panggilan API locationQuery Bing Maps di JavaScript
  • Meneruskan opsi pencarian ke panggilan API
  • Menampilkan hasil pencarian
  • Menangani ID klien Bing dan kunci langganan API
  • Menangani kesalahan yang mungkin terjadi

Halaman tutorial sepenuhnya mandiri; tidak menggunakan kerangka kerja, lembar gaya, atau bahkan file gambar eksternal. Halaman tutorial ini hanya menggunakan fitur bahasa JavaScript yang didukung secara luas dan berfungsi dengan versi saat ini dari semua browser Web utama.

Dalam tutorial ini, kita membahas bagian yang dipilih dari kode sumber. Kode sumber lengkap tersedia di halaman terpisah. Salin dan tempel kode ini ke editor teks dan simpan sebagai bing.html.

Catatan

Tutorial ini secara substansial mirip dengan tutorial aplikasi Bing Web Search satu halaman, tetapi hanya berurusan dengan hasil pencarian entitas.

Prasyarat

Untuk mengikuti tutorial ini, Anda memerlukan kunci langganan untuk Bing Search API dan Bing Maps API.

Komponen aplikasi

Seperti aplikasi Web satu halaman, aplikasi tutorial memiliki tiga bagian:

  • HTML - Menentukan struktur dan konten halaman
  • CSS - Menentukan tampilan halaman
  • JavaScript - Menentukan aktivitas halaman

Tutorial ini tidak mencakup sebagian besar HTML atau CSS secara rinci, karena topik tersebut mudah.

HTML berisi formulir pencarian di mana pengguna memasukkan kueri dan memilih opsi pencarian. Formulir terhubung ke JavaScript yang benar-benar melakukan pencarian dengan <form> atribut onsubmit tag:

<form name="bing" onsubmit="return newBingEntitySearch(this)">

Penangan onsubmit mengembalikan false, yang menjaga agar formulir tidak dikirim ke server. Kode JavaScript melakukan pekerjaan mengumpulkan informasi yang diperlukan dari formulir dan melakukan pencarian.

Pencarian dilakukan dalam dua fase. Pertama, jika pengguna telah memasukkan pembatasan lokasi, kueri Bing Maps dilakukan untuk mengonversinya menjadi koordinat. Panggilan balik untuk kueri ini kemudian memulai kueri Pencarian Entitas Bing.

HTML juga berisi pembagian (tag <div> HTML) tempat hasil pencarian muncul.

Mengelola kunci langganan

Catatan

Aplikasi ini memerlukan kunci langganan untuk Bing Search API dan Bing Maps API.

Agar tidak perlu menyertakan kunci langganan Bing Search API dalam kode, kami menggunakan penyimpanan persisten browser untuk menyimpan kunci. Jika salah satu kunci belum disimpan, kami memintanya dan menyimpannya untuk digunakan nanti. Jika kunci kemudian ditolak oleh API, kami membatalkan kunci yang disimpan sehingga pengguna dimintai kunci tersebut pada pencarian berikutnya.

Tentukan fungsi storeValue dan retrieveValue untuk menggunakan objek localStorage (jika browser mendukungnya) atau cookie. Fungsi getSubscriptionKey() kami menggunakan fungsi-fungsi ini untuk menyimpan dan mengambil kunci pengguna. Anda dapat menggunakan titik akhir global di bawah, atau titik akhir subdomain kustom yang ditampilkan di portal Azure untuk sumber daya Anda.

// cookie names for data we store
SEARCH_API_KEY_COOKIE = "bing-search-api-key";
MAPS_API_KEY_COOKIE   = "bing-maps-api-key";
CLIENT_ID_COOKIE      = "bing-search-client-id";

// API endpoints
SEARCH_ENDPOINT = "https://api.cognitive.microsoft.com/bing/v7.0/entities";
MAPS_ENDPOINT   = "https://dev.virtualearth.net/REST/v1/Locations";

// ... omitted definitions of storeValue() and retrieveValue()

// get stored API subscription key, or prompt if it's not found
function getSubscriptionKey(cookie_name, key_length, api_name) {
    var key = retrieveValue(cookie_name);
    while (key.length !== key_length) {
        key = prompt("Enter " + api_name + " API subscription key:", "").trim();
    }
    // always set the cookie in order to update the expiration date
    storeValue(cookie_name, key);
    return key;
}

function getMapsSubscriptionKey() {
    return getSubscriptionKey(MAPS_API_KEY_COOKIE, 64, "Bing Maps");
}

function getSearchSubscriptionKey() {
    return getSubscriptionKey(SEARCH_API_KEY_COOKIE, 32, "Bing Search");
}

Tag HTML <body> menyertakan atribut onload yang memanggil getSearchSubscriptionKey() dan getMapsSubscriptionKey() setelah halaman selesai dimuat. Panggilan ini berfungsi untuk segera meminta kunci kepada pengguna jika mereka belum memasukkannya.

<body onload="document.forms.bing.query.focus(); getSearchSubscriptionKey(); getMapsSubscriptionKey();">

Memilih opsi pencarian

[Formulir Pencarian Entitas Bing]

Formulir HTML mencakup kontrol berikut:

Kontrol Deskripsi
where Menu drop-down untuk memilih pasar (lokasi dan bahasa) yang digunakan untuk pencarian.
query Bidang teks untuk memasukkan istilah pencarian.
safe Kotak centang yang menunjukkan apakah SafeSearch diaktifkan (membatasi hasil "dewasa")
what Menu untuk memilih pencarian entitas, tempat, atau keduanya.
mapquery Bidang teks di mana pengguna dapat memasukkan alamat penuh atau sebagian, tengara, dll. untuk membantu Pencarian Entitas Bing mengembalikan hasil yang lebih relevan.

Catatan

Hasil tempat saat ini hanya tersedia di Amerika Serikat. Menu where dan what memiliki kode untuk memberlakukan pembatasan ini. Jika Anda memilih pasar non-AS sementara Tempat dipilih di menu what, what berubah menjadi Apa Saja. Jika Anda memilih Tempat sementara pasar non-AS dipilih di menu where, where berubah menjadi AS.

Fungsi JavaScript kami bingSearchOptions() mengonversi bidang ini menjadi string kueri parsial untuk Bing Search API.

// build query options from the HTML form
function bingSearchOptions(form) {

    var options = [];
    options.push("mkt=" + form.where.value);
    options.push("SafeSearch=" + (form.safe.checked ? "strict" : "off"));
    if (form.what.selectedIndex) options.push("responseFilter=" + form.what.value);
    return options.join("&");
}

Misalnya, fitur SafeSearch bisa jadi strict, moderate, atau off dengan moderate sebagai default. Namun, formulir kami menggunakan kotak centang, yang hanya memiliki dua status. Kode JavaScript mengonversi pengaturan ini menjadi strict atau off (kami tidak menggunakan moderate).

Bidang mapquery tidak ditangani di bingSearchOptions() karena digunakan untuk kueri lokasi Bing Maps, bukan untuk Pencarian Entitas Bing.

Mendapatkan lokasi

Bing Maps API menawarkan metode locationQuery, yang kami gunakan untuk menemukan garis lintang dan bujur dari lokasi yang dimasukkan pengguna. Koordinat ini kemudian diteruskan ke API Pencarian Entitas Bing dengan permintaan pengguna. Hasil pencarian memprioritaskan entitas dan tempat yang dekat dengan lokasi yang ditentukan.

Kami tidak dapat mengakses Bing Maps API menggunakan kueri XMLHttpRequest biasa di aplikasi Web karena layanan tidak mendukung kueri lintas asal. Untungnya, layanan ini mendukung JSONP ("P" adalah untuk "padded"). Respons JSONP adalah respons JSON biasa yang dibungkus dalam panggilan fungsi. Permintaan dibuat dengan menyisipkan menggunakan tag <script> ke dalam dokumen. (Memuat skrip tidak tunduk pada kebijakan keamanan browser.)

Fungsi bingMapsLocate() ini membuat dan menyisipkan tag <script> untuk kueri. Segmen jsonp=bingMapsCallback string kueri menentukan nama fungsi yang akan dipanggil dengan respons.

function bingMapsLocate(where) {

    where = where.trim();
    var url = MAPS_ENDPOINT + "?q=" + encodeURIComponent(where) + 
                "&jsonp=bingMapsCallback&maxResults=1&key=" + getMapsSubscriptionKey();

    var script = document.getElementById("bingMapsResult")
    if (script) script.parentElement.removeChild(script);

    // global variable holds reference to timer that will complete the search if the maps query fails
    timer = setTimeout(function() {
        timer = null;
        var form = document.forms.bing;
        bingEntitySearch(form.query.value, "", bingSearchOptions(form), getSearchSubscriptionKey());
    }, 5000);

    script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.setAttribute("id", "bingMapsResult");
    script.setAttribute("src", url);
    script.setAttribute("onerror", "BingMapsCallback(null)");
    document.body.appendChild(script);

    return false;
}

Catatan

Jika Bing Maps API tidak merespons, fungsi bingMapsCallBack() tidak pernah dipanggil. Biasanya, itu berarti bahwa bingEntitySearch() tidak dipanggil, dan hasil pencarian entitas tidak muncul. Untuk menghindari skenario ini, bingMapsLocate() juga mengatur timer untuk memanggil bingEntitySearch() setelah lima detik. Ada logika dalam fungsi panggilan balik untuk menghindari pencarian entitas dua kali.

Setelah kueri selesai, fungsi bingMapsCallback() dipanggil, seperti yang diminta.

function bingMapsCallback(response) {

    if (timer) {    // we beat the timer; stop it from firing
        clearTimeout(timer);
        timer = null;
    } else {        // the timer beat us; don't do anything
        return; 
    }

    var location = "";
    var name = "";
    var radius = 1000;

    if (response) {
        try {
            if (response.statusCode === 401) {
                invalidateMapsKey();
            } else if (response.statusCode === 200) {
                var resource = response.resourceSets[0].resources[0];
                var coords   = resource.point.coordinates;
                name         = resource.name;

                // the radius is the largest of the distances between the location and the corners
                // of its bounding box (in case it's not in the center) with a minimum of 1 km
                try {
                    var bbox    = resource.bbox;
                    radius  = Math.max(haversineDistance(bbox[0], bbox[1], coords[0], coords[1]),
                                       haversineDistance(coords[0], coords[1], bbox[2], bbox[1]),
                                       haversineDistance(bbox[0], bbox[3], coords[0], coords[1]),
                                       haversineDistance(coords[0], coords[1], bbox[2], bbox[3]), 1000);
                } catch(e) {  }
                var location = "lat:" + coords[0] + ";long:" + coords[1] + ";re:" + Math.round(radius);
            }
        }
        catch (e) { }   // response is unexpected. this isn't fatal, so just don't provide location
    }

    var form = document.forms.bing;
    if (name) form.mapquery.value = name;
    bingEntitySearch(form.query.value, location, bingSearchOptions(form), getSearchSubscriptionKey());

}

Seiring dengan garis lintang dan bujur, kueri Pencarian Entitas Bing memerlukan radius yang menunjukkan presisi informasi lokasi. Kami menghitung radius menggunakan kotak batas yang disediakan dalam respons Bing Maps. Kotak batas adalah persegi panjang yang mengelilingi seluruh lokasi. Misalnya, jika pengguna memasukkan NYC, hasilnya berisi koordinat sekitar pusat Kota New York dan kotak batas yang mencakup kota.

Kami pertama-tama menghitung jarak dari koordinat utama ke masing-masing dari empat sudut kotak batas menggunakan fungsi haversineDistance() (tidak ditampilkan). Kami menggunakan yang terbesar dari empat jarak ini sebagai radius. Radius minimum adalah satu kilometer. Nilai ini juga digunakan sebagai default jika tidak ada kotak batas yang disediakan dalam respons.

Setelah mendapatkan koordinat dan radius, kami kemudian memanggil bingEntitySearch() untuk melakukan pencarian yang sebenarnya.

Berdasarkan kueri, lokasi, string opsi, dan kunci API, fungsi BingEntitySearch() tersebut membuat permintaan Pencarian Entitas Bing.

// perform a search given query, location, options string, and API keys
function bingEntitySearch(query, latlong, options, key) {

    // scroll to top of window
    window.scrollTo(0, 0);
    if (!query.trim().length) return false;     // empty query, do nothing

    showDiv("noresults", "Working. Please wait.");
    hideDivs("pole", "mainline", "sidebar", "_json", "_http", "error");

    var request = new XMLHttpRequest();
    var queryurl = SEARCH_ENDPOINT + "?q=" + encodeURIComponent(query) + "&" + options;

    // open the request
    try {
        request.open("GET", queryurl);
    } 
    catch (e) {
        renderErrorMessage("Bad request (invalid URL)\n" + queryurl);
        return false;
    }

    // add request headers
    request.setRequestHeader("Ocp-Apim-Subscription-Key", key);
    request.setRequestHeader("Accept", "application/json");

    var clientid = retrieveValue(CLIENT_ID_COOKIE);
    if (clientid) request.setRequestHeader("X-MSEdge-ClientID", clientid);

    if (latlong) request.setRequestHeader("X-Search-Location", latlong);

    // event handler for successful response
    request.addEventListener("load", handleBingResponse);
    
    // event handler for erorrs
    request.addEventListener("error", function() {
        renderErrorMessage("Error completing request");
    });

    // event handler for aborted request
    request.addEventListener("abort", function() {
        renderErrorMessage("Request aborted");
    });

    // send the request
    request.send();
    return false;
}

Setelah berhasil menyelesaikan permintaan HTTP, JavaScript memanggil penanga aktivitas load kami, fungsi handleBingResponse(), untuk menangani permintaan GET HTTP ke API yang berhasil .

// handle Bing search request results
function handleBingResponse() {
    hideDivs("noresults");

    var json = this.responseText.trim();
    var jsobj = {};

    // try to parse JSON results
    try {
        if (json.length) jsobj = JSON.parse(json);
    } catch(e) {
        renderErrorMessage("Invalid JSON response");
    }

    // show raw JSON and HTTP request
    showDiv("json", preFormat(JSON.stringify(jsobj, null, 2)));
    showDiv("http", preFormat("GET " + this.responseURL + "\n\nStatus: " + this.status + " " + 
        this.statusText + "\n" + this.getAllResponseHeaders()));

    // if HTTP response is 200 OK, try to render search results
    if (this.status === 200) {
        var clientid = this.getResponseHeader("X-MSEdge-ClientID");
        if (clientid) retrieveValue(CLIENT_ID_COOKIE, clientid);
        if (json.length) {
            if (jsobj._type === "SearchResponse") {
                renderSearchResults(jsobj);
            } else {
                renderErrorMessage("No search results in JSON response");
            }
        } else {
            renderErrorMessage("Empty response (are you sending too many requests too quickly?)");
        }
    if (divHidden("pole") && divHidden("mainline") && divHidden("sidebar")) 
        showDiv("noresults", "No results.<p><small>Looking for restaurants or other local businesses? Those currently areen't supported outside the US.</small>");
    }

    // Any other HTTP status is an error
    else {
        // 401 is unauthorized; force re-prompt for API key for next request
        if (this.status === 401) invalidateSearchKey();

        // some error responses don't have a top-level errors object, so gin one up
        var errors = jsobj.errors || [jsobj];
        var errmsg = [];

        // display HTTP status code
        errmsg.push("HTTP Status " + this.status + " " + this.statusText + "\n");

        // add all fields from all error responses
        for (var i = 0; i < errors.length; i++) {
            if (i) errmsg.push("\n");
            for (var k in errors[i]) errmsg.push(k + ": " + errors[i][k]);
        }

        // also display Bing Trace ID if it isn't blocked by CORS
        var traceid = this.getResponseHeader("BingAPIs-TraceId");
        if (traceid) errmsg.push("\nTrace ID " + traceid);

        // and display the error message
        renderErrorMessage(errmsg.join("\n"));
    }
}

Penting

Permintaan HTTP yang berhasil tidak selalu berarti bahwa pencarian itu sendiri berhasil. Jika terjadi kesalahan dalam operasi pencarian, API Pencarian Entitas Bing mengembalikan kode status HTTP non-200 dan menyertakan informasi kesalahan dalam respons JSON. Selain itu, jika permintaan tersebut dibatasi tarif, API akan mengembalikan respons kosong.

Sebagian besar kode dalam kedua fungsi sebelumnya dikhususkan untuk penanganan kesalahan. Kesalahan dapat terjadi pada tahap berikut:

Tahap Potensi kesalahan Ditangani oleh
Membangun objek permintaan JavaScript URL tidak valid Blok try/catch
Membuat permintaan Kesalahan jaringan, koneksi yang dibatalkan Penanganan aktivitas error dan abort
Melakukan pencarian Permintaan tidak valid, JSON tidak valid, batas tarif pengujian dalam penanganan aktivitas load

Kesalahan ditangani dengan memanggil renderErrorMessage() dengan detail apa pun yang diketahui tentang kesalahan tersebut. Jika respons meneruskan gauntlet lengkap dari pengujian kesalahan, kami memanggil renderSearchResults() untuk menampilkan hasil pencarian di halaman.

Menampilkan hasil pencarian

API Pencarian Entitas Bing mengharuskan Anda untuk menampilkan hasil dalam urutan yang ditentukan. Karena API dapat mengembalikan dua jenis respons yang berbeda, tidak cukup melakukan perulangan melalui koleksi Entities atau Places tingkat atas dalam respons JSON dan menampilkan hasil tersebut. (Jika Anda hanya menginginkan satu jenis hasil, gunakan parameter kueri responseFilter.)

Sebagai gantinya, kami menggunakan koleksi rankingResponse di hasil pencarian untuk mengurutkan hasil untuk ditampilkan. Obyek ini merujuk ke item dalam koleksi Entitiess dan/atau Places.

rankingResponse dapat berisi hingga tiga koleksi hasil pencarian, pole, mainline, dan sidebar yang ditunjuk.

pole, jika ada, adalah hasil pencarian yang paling relevan dan harus ditampilkan dengan jelas. mainline mengacu pada sebagian besar hasil pencarian. Hasil utama harus ditampilkan segera setelah pole (atau pertama, jika pole tidak ada).

Akhirnya. sidebar mengacu pada hasil pencarian tambahan. Hasil tersebut mungkin ditampilkan di bilah samping aktual atau di sebelah hasil utama. Kami telah memilih yang terakhir untuk aplikasi tutorial kami.

Setiap item dalam koleksi rankingResponse mengacu pada item hasil pencarian aktual dalam dua cara yang berbeda, tetapi setara.

Item Deskripsi
id id terlihat seperti URL, tetapi tidak boleh digunakan untuk tautan. Jenis id hasil peringkat cocok dengan id item hasil pencarian dalam koleksi jawaban, atau seluruh koleksi jawaban (seperti Entities).
answerType
resultIndex
answerType mengacu pada koleksi jawaban tingkat atas yang berisi hasilnya (misalnya, Entities). resultIndex mengacu pada indeks hasil dalam koleksi tersebut. Jika resultIndex dihilangkan, hasil peringkat mengacu pada seluruh koleksi.

Catatan

Untuk informasi selengkapnya tentang bagian respons pencarian ini, lihat Hasil Peringkat.

Anda dapat menggunakan metode apa pun untuk menemukan item hasil pencarian yang direferensikan yang paling nyaman untuk aplikasi Anda. Dalam kode tutorial kami, kami menggunakan answerType dan resultIndex untuk menemukan setiap hasil pencarian.

Akhirnya, saatnya untuk melihat fungsi renderSearchResults() kita. Fungsi ini berulang selama tiga koleksi rankingResponse yang mewakili tiga bagian dari hasil pencarian. Untuk setiap bagian, kami memanggil renderResultsItems() untuk merender hasil untuk bagian tersebut.

// render the search results given the parsed JSON response
function renderSearchResults(results) {

    // if spelling was corrected, update search field
    if (results.queryContext.alteredQuery) 
        document.forms.bing.query.value = results.queryContext.alteredQuery;

    // for each possible section, render the results from that section
    for (section in {pole: 0, mainline: 0, sidebar: 0}) {
        if (results.rankingResponse[section])
            showDiv(section, renderResultsItems(section, results));
    }
}

Merender item hasil

Dalam JavaScript kami, kode adalah objek, searchItemRenderers, dapat berisi perender : fungsi yang menghasilkan HTML untuk setiap jenis hasil pencarian.

searchItemRenderers = { 
    entities: function(item) { ... },
    places: function(item) { ... }
}

Fungsi perender dapat menerima parameter berikut:

Parameter Deskripsi
item Objek JavaScript yang berisi properti item, seperti URL dan deskripsinya.
index Indeks item hasil dalam koleksinya.
count Jumlah item dalam koleksi item hasil pencarian.

Parameter index dan count dapat digunakan untuk menomori hasil, untuk menghasilkan HTML khusus untuk awal atau akhir koleksi, untuk menyisipkan hentian baris setelah item dalam jumlah tertentu, dan sebagainya. Jika perender tidak memerlukan fungsionalitas ini, perender tidak perlu menerima kedua parameter ini. Bahkan, kami tidak menggunakannya di perender untuk aplikasi tutorial kami.

Mari kita lihat lebih dekat pada perender entities:

    entities: function(item) {
        var html = [];
        html.push("<p class='entity'>");
        if (item.image) {
            var img = item.image;
            if (img.hostPageUrl) html.push("<a href='" + img.hostPageUrl + "'>");
            html.push("<img src='" + img.thumbnailUrl +  "' title='" + img.name + "' height=" + img.height + " width= " + img.width + ">");
            if (img.hostPageUrl) html.push("</a>");
            if (img.provider) {
                var provider = img.provider[0];
                html.push("<small>Image from ");
                if (provider.url) html.push("<a href='" + provider.url + "'>");
                html.push(provider.name ? provider.name : getHost(provider.url));
                if (provider.url) html.push("</a>");
                html.push("</small>");
            }
        }
        html.push("<p>");
        if (item.entityPresentationInfo) {
            var pi = item.entityPresentationInfo;
            if (pi.entityTypeHints || pi.entityTypeDisplayHint) {
                html.push("<i>");
                if (pi.entityTypeDisplayHint) html.push(pi.entityTypeDisplayHint);
                else if (pi.entityTypeHints) html.push(pi.entityTypeHints.join("/"));
                html.push("</i> - ");
            }
        }
        html.push(item.description);
        if (item.webSearchUrl) html.push("&nbsp;<a href='" + item.webSearchUrl + "'>More</a>")
        if (item.contractualRules) {
            html.push("<p><small>");
            var rules = [];
            for (var i = 0; i < item.contractualRules.length; i++) {
                var rule = item.contractualRules[i];
                var link = [];
                if (rule.license) rule = rule.license;
                if (rule.url) link.push("<a href='" + rule.url + "'>");
                link.push(rule.name || rule.text || rule.targetPropertyName + " source");
                if (rule.url) link.push("</a>");
                rules.push(link.join(""));
            }
            html.push("License: " + rules.join(" - "));
            html.push("</small>");
        }
        return html.join("");
    }, // places renderer omitted

Fungsi perender entitas kami:

  • Menyusun tag <img> HTML untuk menampilkan gambar mini gambar, jika ada.
  • Menyusun tag <a> HTML yang menautkan ke halaman yang berisi gambar.
  • Membuat deskripsi yang menampilkan informasi tentang gambar dan situs tempatnya berada.
  • Menggabungkan klasifikasi entitas menggunakan petunjuk tampilan, jika ada.
  • Menyertakan tautan ke Bing Search untuk mendapatkan informasi lebih lanjut tentang entitas tersebut.
  • Menampilkan informasi lisensi atau atribusi yang diperlukan oleh sumber data.

ID klien tetap

Respons dari Bing Search API dapat menyertakan header X-MSEdge-ClientID yang harus dikirim kembali ke API dengan permintaan yang berurutan. Jika beberapa Bing Search API sedang digunakan, ID klien yang sama harus digunakan dengan semuanya, jika memungkinkan.

Menyediakan header X-MSEdge-ClientID memungkinkan Bing API untuk mengaitkan semua pencarian pengguna, yang memiliki dua manfaat penting.

Pertama, herader ini memungkinkan mesin pencari Bing untuk menerapkan konteks masa lalu ke pencarian untuk menemukan hasil yang lebih memuaskan pengguna. Jika pengguna sebelumnya telah mencari istilah yang terkait dengan berlayar, misalnya, pencarian berikutnya untuk "dermaga" akan lebih disukai jika mengembalikan informasi tentang tempat-tempat untuk memarkir perahu layar.

Kedua, Bing dapat secara acak memilih pengguna untuk mencoba fitur baru sebelum fitur tersebut tersedia secara luas. Memberikan ID klien yang sama dengan setiap permintaan memastikan bahwa pengguna yang terpilih untuk melihat fitur, akan selalu melihat fitur tersebut. Tanpa ID klien, pengguna mungkin melihat fitur muncul dan menghilang, tampaknya secara acak, dalam hasil pencarian mereka.

Kebijakan keamanan browser (CORS) dapat mencegah header X-MSEdge-ClientID tersedia di JavaScript. Pembatasan ini terjadi ketika respons pencarian memiliki asal yang berbeda dari halaman yang memintanya. Dalam lingkungan produksi, Anda harus menangani kebijakan ini dengan menghosting skrip sisi server yang melakukan panggilan API pada domain yang sama dengan halaman Web. Karena skrip memiliki asal yang sama dengan halaman Web, header X-MSEdge-ClientID kemudian tersedia untuk JavaScript.

Catatan

Dalam aplikasi Web produksi, Anda harus tetap melakukan permintaan sisi server. Jika tidak, kunci Bing Search API Anda harus disertakan di halaman Web, yang tersedia bagi siapa saja yang melihat sumber. Anda ditagih untuk semua penggunaan pada kunci langganan API, bahkan permintaan yang dibuat oleh pihak yang tidak berwenang, jadi penting untuk tidak menunjukkan kunci Anda.

Untuk tujuan pengembangan, Anda dapat membuat permintaan Bing Web Search API melalui proksi CORS. Respons dari proksi semacam itu memiliki header Access-Control-Expose-Headers yang mengizinkan header respons dan menyediakannya untuk JavaScript.

Sangat mudah untuk memasang proksi CORS untuk mengizinkan aplikasi tutorial kami mengakses header ID klien. Pertama, jika Anda belum memilikinya, pasang Node.js. Kemudian, keluarkan perintah berikut di jendela perintah:

npm install -g cors-proxy-server

Selanjutnya, ubah titik akhir Bing Web Search dalam file HTML menjadi:
http://localhost:9090/https://api.cognitive.microsoft.com/bing/v7.0/search

Terakhir, mulai proksi CORS dengan perintah berikut:

cors-proxy-server

Biarkan jendela perintah terbuka saat Anda menggunakan aplikasi tutorial; menutup jendela akan menghentikan proksi. Di bagian Header HTTP yang dapat diluaskan di bawah hasil pencarian, Anda sekarang dapat melihat header X-MSEdge-ClientID (di antara yang lain) dan memverifikasi bahwa header tersebut sama untuk setiap permintaan.

Langkah berikutnya