Condividi tramite


Esercitazione: App a pagina singola Ricerca video

Avviso

Il 30 ottobre 2020 le API Ricerca Bing sono state spostate dai servizi di intelligenza artificiale di Azure ai servizi di Ricerca Bing. Questa documentazione viene fornita solo per riferimento. Per la documentazione aggiornata, vedere la documentazione dell'API ricerca Bing. Per istruzioni sulla creazione di nuove risorse di Azure per la ricerca Bing, vedere Creare una risorsa Ricerca Bing tramite il Azure Marketplace.

L'API Ricerca video Bing consente di eseguire ricerche sul Web e di ottenere come risultati video pertinenti a una query di ricerca. In questa esercitazione viene compilata un'applicazione Web a pagina singola che usa l'API Ricerca video Bing per visualizzare i risultati della ricerca nella pagina. L'applicazione include componenti HTML, CSS e JavaScript.

Nota

Quando si fa clic sulle intestazioni JSON e HTTP nella parte inferiore della pagina vengono visualizzate le informazioni relative alla risposta JSON e alla richiesta HTTP. Questi dettagli possono essere utili durante l'esplorazione del servizio.

Risultati non elaborati HTTP JSON

L'app dell'esercitazione illustra come:

  • Eseguire una chiamata all'API Ricerca video Bing in JavaScript
  • Passare le opzioni di ricerca all'API di ricerca Bing
  • Visualizzare i risultati della ricerca video o, facoltativamente, includere immagini, notizie o pagine Web
  • Intervalli di tempo per la ricerca di 24 ore, l'ultima settimana, mese o tutto il tempo disponibile
  • Sfogliare i risultati della ricerca
  • Gestire l'ID del client Bing e la chiave di sottoscrizione dell'API
  • Gestire gli errori che potrebbero verificarsi

La pagina dell'esercitazione è autonoma, non usa framework, fogli di stile o file di immagine esterni. Usa solo funzionalità del linguaggio JavaScript ampiamente supportate e funziona con le versioni correnti di tutti i Web browser principali.

Questa esercitazione illustra parti selezionate del codice sorgente. È disponibile il codice sorgente completo. Per eseguire l'esempio, copiare e incollare il codice sorgente in un editor di testo e salvarlo come bing.html.

Componenti dell'app

Come qualsiasi applicazione Web a pagina singola, questa applicazione di esercitazione include tre parti:

  • HTML, che definisce la struttura e il contenuto della pagina
  • CSS, che definisce l'aspetto della pagina
  • JavaScript, che definisce il comportamento della pagina

La maggior parte del codice HTML e CSS è convenzionale, pertanto l'esercitazione non lo descrive. Il codice HTML contiene il modulo di ricerca in cui l'utente immette una query e sceglie le opzioni di ricerca. Il modulo è connesso a JavaScript che esegue la ricerca usando l'attributo onsubmit del tag <form>:

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

Il gestore onsubmit restituisce false, che impedisce che il modulo venga inviato a un server. Il codice JavaScript esegue le operazioni di raccolta delle informazioni necessarie dal modulo ed esegue la ricerca.

Il codice HTML contiene anche le divisioni, ovvero tag HTML <div>, in cui vengono visualizzati i risultati della ricerca.

Gestione della chiave di sottoscrizione

Per evitare di includere la chiave di sottoscrizione dell'API di ricerca Bing nel codice, viene usata l'archiviazione permanente del browser per archiviare la chiave. Prima che la chiave venga archiviata, viene richiesta la chiave dell'utente. Se in un secondo momento la chiave viene rifiutata dall'API, la chiave archiviata viene invalidata e l'utente riceverà nuovamente la richiesta.

Vengono definite le funzioni storeValue e retrieveValue che usano l'oggetto localStorage, non supportato da tutti i browser, o un cookie. La funzione getSubscriptionKey() usa queste funzioni per archiviare e recuperare la chiave dell'utente.

// Cookie names for data we store
API_KEY_COOKIE   = "bing-search-api-key";
CLIENT_ID_COOKIE = "bing-search-client-id";

// ... omitted definitions of store value and retrieve value
// Browsers differ in their support for persistent storage by 
// local HTML files. See the source code for browser-specific
// options.

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

Il tag onsubmit HTML <form> chiama la funzione bingWebSearch per restituire i risultati della ricerca. bingWebSearch usa getSubscriptionKey() per autenticare ciascuna query. Come indicato nella definizione precedente, getSubscriptionKey richiede all'utente la chiave se non è stata immessa. La chiave viene quindi archiviata per continuare a essere usata dall'applicazione.

<form name="bing" onsubmit="this.offset.value = 0; return bingWebSearch(this.query.value, 
    bingSearchOptions(this), getSubscriptionKey())">

Selezione delle opzioni di ricerca

La figura seguente mostra la casella di testo della query e le opzioni che definiscono una ricerca.

Opzioni di Ricerca notizie Bing

Il modulo HTML include elementi con i nomi seguenti:

Elemento Descrizione
where Un menu a discesa per la selezione del mercato (località e lingua) usato per la ricerca.
query Il campo di testo in cui inserire i termini di ricerca.
modules Caselle di controllo per alzare di livello determinati moduli di risultati, tutti i risultati o i video correlati.
when Menu a discesa per limitare facoltativamente la ricerca all'ultimo giorno, settimana o mese.
safe Una casella di controllo che indica se usare la funzionalità SafeSearch di Bing per filtrare i risultati con contenuti "per soli adulti".
count Campo nascosto. Il numero di risultati della ricerca da restituire per ogni richiesta. Modificarlo per visualizzare un numero maggiore o minore di risultati per pagina.
offset Campo nascosto. Lo scostamento del primo risultato della ricerca nella richiesta; utilizzato per il paging. Viene reimpostato su 0 per una nuova richiesta.

Nota

Ricerca Web Bing offre altri parametri di query. Qui ne vengono usati solo alcuni.

// build query options from the HTML form
// 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" : "moderate"));

    if (form.when.value.length) options.push("freshness=" + form.when.value);
    var what = [];
    for (var i = 0; i < form.what.length; i++) 
        if (form.what[i].checked) what.push(form.what[i].value);
    if (what.length) {
        options.push("modules=" + what.join(","));
        options.push("answerCount=9");
    }
    options.push("count=" + form.count.value);
    options.push("offset=" + form.offset.value);
    options.push("textDecorations=true");
    options.push("textFormat=HTML");
    return options.join("&");
}

Ad esempio, il parametro SafeSearch in una chiamata API effettiva può essere strict o moderate, con moderate come valore predefinito.

Esecuzione della richiesta

Ricevuta la query, la stringa delle opzioni e la chiave API, la funzione BingWebSearch usa un oggetto XMLHttpRequest per effettuare la richiesta all'endpoint di Ricerca Bing. È possibile usare l'endpoint globale seguente o l'endpoint sottodominio personalizzato visualizzato nel portale di Azure per la risorsa.

// Search on the query, using search options, authenticated by the key.
function bingWebSearch(query, 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", "_headers", "paging1", "paging2", "error");

    var endpoint = "https://api.cognitive.microsoft.com/bing/v7.0/videos/search";
    var request = new XMLHttpRequest();
    var queryurl = endpoint + "?q=" + encodeURIComponent(query) + "&" + options;

    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);

    // event handler for successful response
    request.addEventListener("load", handleOnLoad);

    // 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;
}

Al completamento corretto della richiesta HTTP, JavaScript chiama il gestore dell'evento load, handleOnLoad(), per gestire una richiesta HTTP GET corretta all'API.

// handle Bing search request results
function handleOnLoad() {
    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 headers
    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 === "Videos") {//"SearchResponse" && "rankingResponse" in jsobj) {
                renderSearchResults(jsobj);
            } else {
                renderErrorMessage("No search results in JSON response");
            }
        } else {
            renderErrorMessage("Empty response (are you sending too many requests too quickly?)");
        }
    }

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

        // 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"));
    }
}

Importante

Se si verifica un errore nell'operazione di ricerca, l'API Ricerca notizie Bing restituisce un codice di stato HTTP non-200 e include le informazioni sull'errore nella risposta JSON. Inoltre, se la richiesta era a frequenza limitata, l'API restituisce una risposta vuota. Una richiesta HTTP corretta non indica necessariamente che la ricerca sia andata a buon fine.

La maggior parte del codice in entrambe le funzioni precedenti è dedicata alla gestione degli errori. Possono verificarsi errori nelle fasi seguenti:

Fase Errori potenziali Gestiti da
Compilazione dell'oggetto richiesta JavaScript URL non valido Blocco try/catch
Invio della richiesta Errori di rete, connessioni interrotte Gestori degli eventi error e abort
Esecuzione della ricerca Richiesta non valida, JSON non valido, limiti di frequenza Test nel gestore dell'evento load

Gli errori vengono gestiti chiamando renderErrorMessage() con tutti i dettagli noti dell'errore. Se la risposta supera la serie completa dei test di errore, viene chiamato renderSearchResults() per visualizzare i risultati della ricerca nella pagina.

Visualizzazione dei risultati della ricerca

La funzione principale per la visualizzazione dei risultati della ricerca è renderSearchResults(). Questa funzione accetta la stringa JSON restituita dal servizio Ricerca notizie Bing ed esegue il rendering dei risultati delle notizie e delle ricerche correlate, se presenti.

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

    // add Prev / Next links with result count
    var pagingLinks = renderPagingLinks(results);
    showDiv("paging1", pagingLinks);
    showDiv("paging2", pagingLinks);

    // Render the results to the mainline section
    for (section in { mainline: 0 }) {
         showDiv(section, renderResultsItems(section, results));
    }
}

I risultati della ricerca vengono restituiti come oggetto di primo livello value nella risposta JSON. Questi vengono inviati alla funzione renderResultsItems() che esegue un'iterazione su essi e chiama una funzione per il rendering di ciascun elemento in HTML. Il codice HTML risultante viene restituito a renderSearchResults(), dove viene inserito nella divisione results della pagina.

// render search results
    function renderResultsItems(section, results) {   

        var items = results.value;
        var html = [];
        for (var i = 0; i < items.length; i++) { 
            var item = items[i];
            // collection name has lowercase first letter
            var type = "videos";
            var render = searchItemRenderers[type];
            html.push(render(item, section));  
        }
    return html.join("\n\n");
}

L'API di Ricerca notizie Bing restituisce fino a quattro tipi di risultati correlati, ognuno dei quali nel proprio oggetto di primo livello. ovvero:

Relazione Descrizione
pivotSuggestions Query che sostituiscono una parola pivot nella ricerca originale con una parola diversa. Ad esempio, se si cerca "fiori rossi", una parola pivot potrebbe essere "rossi" e un suggerimento pivot potrebbe essere "fiori gialli".
queryExpansions Query che restringono la ricerca originale con l'aggiunta di nuovi termini. Ad esempio, se si cerca "Microsoft Surface", un'espansione della query potrebbe essere "Microsoft Surface Pro".
relatedSearches Query che sono state inserite anche da altri utenti che hanno immesso la ricerca originale. Ad esempio, se si cerca "Mount Rainier", una ricerca correlata potrebbe essere "Mt. Saint Helens".
similarTerms Query che sono simili nel significato alla ricerca originale. Ad esempio, se si cerca "scuole", un termine simile potrebbe essere "istruzione".

Come illustrato in precedenza in renderSearchResults(), viene eseguito il rendering solo dei suggerimenti relatedItems e i collegamenti risultanti vengono inseriti nella barra laterale della pagina.

Rendering degli elementi di risultati

Nel codice JavaScript l'oggetto searchItemRenderers può contenere renderer: funzioni che generano HTML per ciascun tipo di risultato della ricerca. La pagina di ricerca video usa solo videos. Per vari tipi di renderer, vedere altre esercitazioni.

searchItemRenderers = {
	news: function(item) { ... },
	webPages: function (item) { ... }, 
    images: function(item, index, count) { ... },
    videos: function (item, section, index, count) { ... },
    relatedSearches: function(item) { ... }
}

Una funzione renderer può accettare i parametri seguenti:

Parametro Descrizione
item L'oggetto JavaScript che contiene le proprietà dell'elemento, ad esempio l'URL e la relativa descrizione.
index L'indice dell'elemento di risultato all'interno della raccolta.
count Il numero di elementi nella raccolta degli elementi di risultati della ricerca.

I parametri index e count possono essere usati per numerare i risultati, per generare codice HTML speciale per l'inizio o la fine di una raccolta, per inserire le interruzioni di riga dopo un certo numero di elementi e così via. Se un renderer non necessita di questa funzionalità, non è necessario che accetti questi due parametri.

Il video renderer è illustrato nell'estratto JavaScript seguente. Utilizzando endpoint di video, tutti i risultati sono di tipo Videos. I searchItemRenderers sono mostrati nel segmento di codice seguente.

// render functions for various types of search results
    searchItemRenderers = {

    videos: function (item, section, index, count) {
        var height = 60;
        var width = Math.round(height * item.thumbnail.width / item.thumbnail.height);
        var html = [];

        html.push("<p class='images'>");
        html.push("<a href='" + item.hostPageUrl + "'>");
        var title = escapeQuotes(item.name) + "\n" + getHost(item.hostPageDisplayUrl);
        html.push("<img src='" + item.thumbnailUrl + "&h=" + height + "&w=" + width +
            "' height=" + height + " width=" + width + " title='" + title + "' alt='" + title + "'>");
        html.push("</a>");
        html.push("<br>");
        html.push("<nobr><a href='" + item.contentUrl + "'>Video page source</a> - ");
        html.push(title.replace("\n", " (").replace(/([a-z0-9])\.([a-z0-9])/g, "$1.<wbr>$2") + ")</p>");
        return html.join("");
    }
}

La funzione renderer:

  • Crea un tag di paragrafo, lo assegna alla classe images e lo inserisce nella matrice html.
  • Calcola le dimensioni dell'anteprima dell'immagine: la larghezza è fissa a 60 pixel, l'altezza è calcolata in proporzione.
  • Compila il tag HTML <img> per visualizzare l'anteprima dell'immagine.
  • Compila i tag HTML <a> che collegano l'immagine e la pagina che la contiene.
  • Compila la descrizione che consente di visualizzare informazioni sull'immagine e il sito in cui si trova.

La dimensione dell'anteprima viene usata sia nel tag <img> che nei campi h e w dell'URL dell'anteprima. Bing restituisce un'anteprima esattamente di quelle dimensioni.

ID client persistente

Le risposte dalle API di ricerca Bing potrebbero includere un'intestazione X-MSEdge-ClientID che deve essere inviata di nuovo all'API con le richieste successive. Se vengono usate più API di ricerca Bing, usare se possibile lo stesso ID client con tutte le API.

Fornire l'intestazione X-MSEdge-ClientID consente alle API Bing di associare tutte le ricerche di un utente, cosa che presenta due vantaggi importanti.

Innanzitutto, consente al motore di ricerca Bing di applicare un contesto passato alle ricerche per trovare i risultati che meglio soddisfano l'utente. Se un utente ha cercato in precedenza termini correlati alla navigazione, ad esempio, una successiva ricerca di "nodi" potrebbe restituire preferibilmente informazioni sui nodi utilizzati nella navigazione.

In secondo luogo, Bing potrebbe selezionare utenti in modo casuale per provare nuove funzionalità prima di renderle disponibili. Fornire lo stesso ID client per tutte le richieste fa sì che gli utenti che visualizzano la funzione la visualizzino sempre. Senza un ID client, l'utente potrebbe vedere una funzionalità apparire e scomparire apparentemente in modo casuale nei risultati delle ricerche.

I criteri di sicurezza del browser (CORS) potrebbero impedire che l'intestazione X-MSEdge-ClientID sia disponibile per JavaScript. Questa limitazione si verifica quando la risposta della ricerca ha un'origine diversa dalla pagina che l'ha richiesta. In un ambiente di produzione è necessario soddisfare questo criterio tramite l'hosting di uno script sul lato server che esegue la chiamata API nello stesso dominio della pagina Web. Poiché lo script ha la stessa origine della pagina Web, l'intestazione X-MSEdge-ClientID diventa disponibile per JavaScript.

Nota

In un'applicazione Web di produzione è necessario effettuare la richiesta lato server. In caso contrario, la chiave dell'API di ricerca Bing deve essere inclusa nella pagina Web, dove sarà disponibile per chiunque visualizzi l'origine. All'utente vengono addebitati costi per tutto l'utilizzo della chiave di sottoscrizione API, anche le richieste effettuate da parti non autorizzate, pertanto è importante che la chiave non sia visibile.

A scopo di sviluppo, è possibile effettuare la richiesta API Ricerca Web Bing tramite un proxy CORS. La risposta da un proxy di questo tipo ha un'intestazione Access-Control-Expose-Headers che accetta le intestazioni di risposta e le rende disponibili a JavaScript.

È facile installare un proxy CORS per consentire all'applicazione di esercitazione di accedere all'intestazione ID client. Per prima cosa installare Node.js, se non è già disponibile. Digitare quindi il comando seguente in una finestra di comando:

npm install -g cors-proxy-server

Poi modificare l'endpoint di Ricerca Web Bing nel file HTML in:
http://localhost:9090/https://api.cognitive.microsoft.com/bing/v7.0/search

Infine avviare il proxy CORS con il comando seguente:

cors-proxy-server

Lasciare aperta la finestra di comando mentre si usa l'app dell'esercitazione. La chiusura della finestra determina l'arresto del proxy. Nella sezione Intestazioni HTTP espandibile sotto i risultati della ricerca è ora possibile visualizzare l'intestazione X-MSEdge-ClientID (tra le altre) e verificare che sia la stessa per ogni richiesta.

Passaggi successivi