0%

AJAX

AJAX 全名為 Asynchronous JavaScript and XML(非同步 JavaScript 及 XML)

  • AJAX 是一種用於創建快速動態網頁的技術。
  • 在傳統的網頁(不使用 AJAX)如果需要更新內容,必須重載整個頁面。而AJAX 通過在後台與伺服器進行少量數據交換,使網頁實現異步更新。這意味著可以在不重載整個頁面的情況下,對網頁的某些部分進行更新。

XMLHttpRequest

Javascript

實例物件 const XHR = new XMLHttpRequest();
要送出一個 HTTP 請求,需要建立一個 XMLHttpRequest 物件、開啟一個 URL,並發起一個請求。

readyState will be 0

設定請求 XMLHttpRequest.open(method, url, async);
  • method:要使用的HTTP方法,比如「GET」、「POST」、「PUT」、「DELETE」、等。
  • url:要向其發送請求的URL。
  • async:其取得資料的方式可以為非同步(asynchronously)或同步(synchronously)兩種之一。默認為true。
    • true:非同步 - 不等資料回傳,程式會繼續執行。
    • false:同步 - 等資料回傳後,程式才會繼續執行。
  • readyState will be 1

    請求表頭 XMLHttpRequest.setRequestHeader(header, value);
    使用 post 時,需透過 setRequestHeader() 方法,設置請求訊息的表頭欄位。
    監聽事件 XMLHttpRequest.onload = callback;
    使用非同步時,需監聽 load 事件,當 XMLHttpRequest 請求成功完成後執行相對應的函式 — 回調函式 (callback)。
    發送請求 XMLHttpRequest.send()
    用於發送 HTTP 請求。如果是非同步請求(默認為異步請求),則此方法會在請求發送後立即返回;如果是同步請求,則此方法直到響應到達後才會返回。
    如請求使用 GET 方法,設為空值: null

    readyState will be 2

    處理回應
    回應的文字 text,可透過 responseText 屬性取得,
    若 Server 回應的是 XML 或 XHTML,則使用 responseXML 屬性,
    若回應的是常見的 JSON,則可以使用 JSON.parse() 方法,解析 responseText 屬性。

    readyState

    Value Status Description
    0 UNSENT XMLHttpRequest() 已被建立,但 open() 方法尚未被呼叫。
    1 OPENED open() 方法已被呼叫,但未傳送任何資料。
    於此狀態時,可以使用 setRequestHeader() 方法設定請求標頭(request headers),並可呼叫 send() 方法來發送請求。
    2 HEADERS_RECEIVED send() 方法已被呼叫,並且已接收到回應標頭(response header)。
    3 LOADING 回應資料下載中,此時 responseText 會擁有部分資料。
    4 DONE 請求操作已完成。這意味著資料傳輸可能已成功完成或是已失敗。

    HTTP狀態碼

    HTTP 狀態碼指的是從伺服器端回應(HTTP Response)的狀態,對於狀態的分類可區分三個層級,分別用三個數字表示,第一個數字為大類、第二個數字為中類、第三個數字為小類。
    完整的狀態碼定義可以參考 10 Status Code Definitions 章節,裡面有完整且詳盡的說明。

    Syntax
    XMLHttpRequest.status
    從上列的語法中可得知目前的狀態,是否有成功回應又或者獲取失敗等等。

    HTTP 狀態碼大致分成 5 類。

    1xx - 參考資訊 (Informational)
    這些狀態碼代表主機先暫時回應用戶端一個狀態,所以在接收一般的回應之前,用戶端應準備接收一個或多個 1xx 的回應。

    • 100 - 繼續。
    • 101 - 切換通訊協定。

    2xx - 成功 (OK)
    這類的狀態碼表示伺服器成功接收到用戶端要求、理解用戶端要求、以及接受用戶端要求。

    • 200 - 確定。 用戶端要求成功
    • 201 - 已建立。
    • 202 - 已接受。
    • 203 - 非授權資訊。
    • 204 - 無內容。
    • 205 - 重設內容。
    • 206 - 部分內容。
    • 207 - 多重狀態 (WebDAV) – 這好像只有在 IIS 中才有,HTTP/1.1 並沒有定義這個狀態。這狀態會出現在可以包含多個不同回應代碼 (視子要求數量而定) 的 XML 訊息之前。

    3xx - 重新導向 (Redirection)
    用戶端瀏覽器必須採取更多動作才能完成要求。例如:瀏覽器可能必須重新發出 HTTP Request 要求伺服器上的不同頁面。

    • 301 - 要求的網頁已經永久改變網址。此狀態要求用戶端未來在連結此網址時應該導向至指定的 URI。
    • 302 - 物件已移動,並告知移動過去的網址。針對表單架構驗證,這通常表示為「物件已移動」。 要求的資源暫時存於不同的 URI 底下。 由於重新導向可能偶而改變,用戶端應繼續使用要求 URI 來執行未來的要求。 除非以 Cache-Control 或 Expires 標頭欄位表示,此回應才能夠快取。
    • 303 - 通知 Client 連到另一個網址去查看上傳表單的結果(POST 變成 GET),當使用程式作網頁轉向時,會回應此訊息。
    • 304 - 未修改。用戶端要求該網頁時,其內容並沒有變更,應該回傳 304 告知網頁未修改。此時用戶端僅需要取得本地快取(Local Cache)的副本即可。
    • 305 - 要求的網頁必須透過 Server 指定的 proxy 才能觀看 ( 透過 Location 標頭 )
    • 306 - (未使用) 此代碼僅用來為了向前相容而已。
    • 307 - 暫時重新導向。要求的網頁只是「暫時」改變網址而已。

    4xx - 用戶端錯誤 (Client Error)
    這代表錯誤發生,且這錯誤的發生的原因跟「用戶端」有關。例如:用戶端可能連結到不存在的頁面、用戶端的權限不足、或可能未提供有效的驗證資訊(輸入的帳號、密碼錯誤)。

    • 400 - 錯誤的要求。
    • 401 - 拒絕存取。 IIS 定義數個不同的 401 錯誤,以表示更詳細的錯誤原因。 這些特定的錯誤碼會顯示在瀏覽器中,但不會顯示在 IIS 記錄檔中:
      • 401.1 - 登入失敗。
      • 401.2 - 因為伺服器設定導致登入失敗。
      • 401.3 - 因為資源上的 ACL 而沒有授權。
      • 401.4 - 篩選授權失敗。
      • 401.5 - ISAPI/CGI 應用程式授權失敗。
      • 401.7 - Web 伺服器上的 URL 授權原則拒絕存取。 這是 IIS 6.0 專用的錯誤碼。
    • 403 - 禁止使用。 IIS 定義數個不同的 403 錯誤,以表示更詳細的錯誤原因:
      • 403.1 - 禁止執行存取。
      • 403.2 - 禁止讀取存取。
      • 403.3 - 禁止寫入存取。
      • 403.4 - 需要 SSL。
      • 403.5 - 需要 SSL 128。
      • 403.6 - IP 位址遭拒。
      • 403.7 - 需要用戶端憑證。
      • 403.8 - 網站存取遭拒。
      • 403.9 - 使用者過多。
      • 403.10 - 設定無效。
      • 403.11 - 密碼變更。
      • 403.12 - 對應程式拒絕存取。
      • 403.13 - 用戶端憑證已撤銷。
      • 403.14 - 目錄清單遭拒。
      • 403.15 - 超過用戶端存取授權數量。
      • 403.16 - 用戶端憑證不受信任或無效。
      • 403.17 - 用戶端憑證已經過期或尚未生效。
      • 403.18 - 無法在目前的應用程式集區中執行要求的 URL。 這是 IIS 6.0 專用的代碼。
      • 403.19 - 無法在這個應用程式集區中執行用戶端的 CGI。 這是 IIS 6.0 專用的代碼。
      • 403.20 - Passport 登入失敗。 這是 IIS 6.0 專用的錯誤碼。
    • 404 - 找不到
      • 404.0 - (無) – 找不到檔案或目錄。
      • 404.1 - 無法在要求的連接埠上存取網站。
      • 404.2 - 網頁服務延伸鎖定原則阻止這個要求。
      • 404.3 - MIME 對應原則阻止這個要求。
    • 405 - 用來存取這個頁面的 HTTP 動詞不受允許 (方法不受允許)。
    • 406 - 用戶端瀏覽器不接受要求頁面的 MIME 類型。
    • 407 - 需要 Proxy 驗證。
    • 412 - 指定條件失敗。
    • 413 - 要求的實體太大。
    • 414 - 要求 URI 太長。
    • 415 - 不支援的媒體類型。
    • 416 - 無法滿足要求的範圍。
    • 417 - 執行失敗。
    • 423 - 鎖定錯誤。

    5xx - 伺服器錯誤 (Server Error)
    這代表錯誤發生,且這錯誤發生的原因跟「伺服器」有關。伺服器因為發生錯誤或例外狀況(Exception)而無法完成要求(Request)時,就會回應 5xx 的錯誤,且這肯定跟伺服器有關。

    • 500 - 內部伺服器錯誤。
      • 500.12 - 應用程式正忙於在 Web 伺服器上重新啟動。
      • 500.13 - Web 伺服器過於忙碌。
      • 500.15 - 不允許直接要求 Global.asa。
      • 500.16 – UNC 授權認證不正確。 這是 IIS 6.0 專用的錯誤碼。
      • 500.18 – 無法開啟 URL 授權存放區。 這是 IIS 6.0 專用的錯誤碼。
      • 500.19 - 此檔案的資料在 Metabase 中設定不當。
      • 500.100 - 內部的 ASP 錯誤。
    • 501 – 標頭值指定未實作的設定。
    • 502 - Web 伺服器在作為閘道或 Proxy 時收到無效的回應。
      • 502.1 - CGI 應用程式逾時。
      • 502.2 - CGI 應用程式中發生錯誤。
    • 503 - 服務無法使用。 這是 IIS 6.0 專用的錯誤碼。
    • 504 - 閘道逾時。
    • 505 - 不支援的 HTTP 版本。

    CORS

    CORS - 跨來源資源共用(Cross-Origin Resource Sharing (CORS))是一種使用額外 HTTP 標頭令目前瀏覽網站的使用者代理取得存取其他來源(網域)伺服器特定資源權限的機制。
    當使用者代理請求一個不是目前文件來源——例如來自於不同網域(domain)、通訊協定(protocol)或通訊埠(port)的資源時,會建立一個跨來源 HTTP 請求(cross-origin HTTP request)。

    CORS測試網站

    傳統表單輸入

    <form action="index.html" method='post'>
    <label for="account">帳號</label>
    <input type="text" id="account" name="account"><br>
    <label for="password">密碼</label>
    <input type="password" id="password" name="password">
    <input type="submit" value='送出'>
    </form>
    • action - 用來設定接收程式。
    • method - 則是資料傳遞的方式 : GETPOST
      GET POST
      網址差異 網址會帶有 HTML Form 表單的參數與資料。 網址並不會改變。
      資料傳遞量 透過 URL 帶資料,所以有長度限制。 不透過 URL 帶參數,所以不受限於 URL 長度限制。
      安全性 表單參數與填寫內容可在 URL 看到。 透過 HTTP Request 方式,故參數與填寫內容不會顯示於 URL。

    當按下 submit 按鈕將表單送出後,HTML 會將表單內的資料以 URL?表單資訊 ,如果有多組內容則會以 & 連接,並進行傳送。

    AJAX POST

    設定請求 XMLHttpRequest.open('post', 'API_URL', true);
    要傳送表單資訊,method 須改為 psot
    請求表頭 XMLHttpRequest.setRequestHeader(header, value);
    要傳送內容的格式,header 屬性為Content-type
    HTML 表單(form)提交方式:
  • 使用 POST 方法,並且設定 value 屬性為 application/x-www-form-urlencoded(HTML5 表單 預設編碼方式)。
  • 使用 POST 方法,並且設定 value 屬性為 multipart/form-data(傳送檔案)。
  • 常見的 application/json 或 application/octet-stream,使用上也是如出一轍
  • 發送請求 XMLHttpRequest.send();
    XMLHttpRequest.send('表單資訊')
    HTML5 表單 預設編碼方式 - Content-type: application/x-www-form-urlencoded ;表單資訊如有多個欄位需使用 & 來連接。
    JSON傳遞 - Content-type: application/json ;表單資訊使用 JSON.stringify 轉型成 string 格式再進行傳送。

    GET

    const xhr = new XMLHttpRequest();
    const URL = 'https://gank.io/api/random/data/福利/20';
    xhr.open('GET', URL, true);
    // 非同步模式,需監聽 load 事件,並於請求成功完成後執行 callback function。
    xhr.onload = function() {
    let data = JSON.parse(xhr.responseText)
    console.log(data);
    }
    xhr.send(null);

    POST

    1. HTML5 表單
      使用 HTML5 表單 傳送資料到 serve ,表單資訊如有多個欄位需使用 & 來連接。

      const xhr = new XMLHttpRequest();
      const URL = 'https://hexschool-tutorial.herokuapp.com/api/signup';
      xhr.open('post', URL, true);
      // 設定檔頭格式為 HTML5 表單 格式
      xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
      xhr.send('email=abcdd@gmail.com&password=123456');
    2. JSON
      使用 JSON 傳送資料到 serve ,JSON 需轉成字串格式。

      const xhr = new XMLHttpRequest();
      const URL = 'https://hexschool-tutorial.herokuapp.com/api/signup';
      const account = { email: 'ttest@hexschool.com', password: 'ttest12345678' }
      xhr.open('post', URL, true);
      // 設定檔頭格式為 JSON 格式
      xhr.setRequestHeader('Content-type', 'application/json');
      xhr.send(JSON.stringify(account));

    Fetch API

    以往都是依賴 XMLHttpRequest。Fetch API 提供了一個能獲取包含跨網路資源在的資源介面,但這個新的 API 提供了更強更彈性的功能,其使用 Promise 作為基本構造要素。
    並被廣泛使用在 Service Workers。Fetch 在設定 HTTP 相關的設定時, 也提供可讀性比較好的方法, 這些設定包括 CORS 以及其他 header。

    Fetch 基本用法

    Syntax
    fetch(input, {init})
    .then(function(response) {
    // 處理 response
    }).catch(function(err) {
    // 錯誤處理
    });
    • fetch 會使用 ES6 的 Promise 作回應
      • .then(onFulfilled, onRejected) 作為下一步
      • catch() 作為錯誤回應 (404, 500…)
    • 回傳的為 Response 物件,需要使用不同資料類型使用對應方法,才能正確取得資料物件。
    input
    定義你想要fetch的資源。
    • 一個直接包含你希望fetch的資源的URL
    • 一個 Request 對象
    init
    可選對象,包含希望被包括到請求中的各種自定義選項。
    屬性 設定值
    method 請求的方法:GET、POST、PUT、DELETE、HEAD ( 預設 GET )
    headers 要求相關的 Headers 物件 ( 預設 {} )
    mode 請求的模式:cors、no-cors、same-origin、navigate ( 預設 cors )
    referrer no-referrer、client 或一個 URL ( 預設 client )
    credentials 請求中想要使用的credentials:omit、same-origin、include ( 預設 omit )
    redirect 對重定向處理的模式:follow、error、manual ( 預設 manual )
    cache 請求中想要使用的cache mode:default、no-store、reload、no-cache、force-cache ( 預設 default )
    body 要加到要求中的內容。
  • 可以是Blob, BufferSource, FormData, URLSearchParams, 或 USVString對象
  • method 為 GET 或 HEAD 則不設定
  • 更多屬性請參考 fetch Request
    屬性 設定值
    headers 包含與 response 相關的 Headers 物件
    ok 成功回傳 true,不成功回傳 false
    status 包含此 response 的狀態碼(例如:成功時為 200 )。
    statusText 包含狀態碼所對應的狀態文字 (例如: OK 對應 200)。
    type 包含此 response 的類型 (例如: basic, cors)。
    url 包含此 response 的 URL。

    更多屬性和方法請參考 fetch Response

    方法 設定值
    .json() 讀取 Response 對象,並返回一個被解析為 JSON 格式的 Promise 對象。
    .text() 讀取 Response 對象,並返回一個被解析為 string 格式的 Promise 對象。
    .blob() 讀取 Response 對象,並返回一個被解析為 blob 格式的 Promise 對象 ( 非結構化物件資料,例如文字或二進位資料 )。
    .arrayBuffer() 讀取 Response 對象,並返回一個被解析為 arrayBuffer 格式的 Promise 對象( 有多少 bytes )。
    .formData() 讀取 Response 對象,並返回一個被解析為 formData 格式的 Promise 對象( 表單資料對應的的 Key 或 Value )。
    .clone() 建立 Response 的複製物件
    .error() 返回一個錯誤的新的 Response 對象。

    更多屬性和方法請參考 fetch Response

    GET

    最簡單的方式只需要一個參數就是資料的 URL,fetch 會回傳一個包含 Response 的 promise ,針對不同資料類型使用對應方法處理此 ResponsereturnResponse 再將資料傳到下一個 then()

    fetch('https://gank.io/api/random/data/福利/20')
    .then((response) => {
    console.log(response)
    return response.json()
    }).then((myJson) => {
    console.log(myJson)
    })
    • fetch() 函式會回傳一個 Promise,並在解析/完成 (resolve) 後,回傳 Response 物件。
    • Response 資訊內包含了請求的 url 和用來判斷請求是否成功的 status 狀態等。
    • 針對不同資料類型使用其對應方法,才能正確取得資料物件,return 已解析的資料並傳給第二個 .then() 接收。
      • return 使用的 .json() ,能夠將回傳的資料以物件的方式傳給第二個 .then() 接收。
      • 當回傳的資料無法轉換為物件時,則會將請求資料以字串 .text() 方式取出。

    POST

    • POST請求需外在 method 屬性內指定 POST 方式。
    • body 屬性指定要送出的資料。
      • 需要注意的是, body 內的資料需使用 JSON.stringify 將物件轉換成字串型態,否則 server 端會無法正確取得資料。
    const url = 'https://hexschool-tutorial.herokuapp.com/api/signup';
    const account = {
    email: 'hex123456789@gmail.com',
    password: '12345678'
    }

    fetch(url, {
    method: 'POST',
    // body 將 json 轉字串送出
    body: JSON.stringify(account),
    // headers 加入 json 格式
    headers: {'Content-type': 'application/json'}
    }).then((response) => {
    return response.json()
    }).then((myJson)=>{
    console.log(myJson)
    })

    請求失敗

    請求失敗須從 Responsestatus 的屬性值判斷,當 status 的值不等於 200 時,將在 .then() 中使用 throw 創建一個錯誤,並由 .catch() 接收錯誤內容。

    fetch('https://httpbin.org/status/404', {
    }).then((response) => {
    if(response.status !== 200)
    throw new Error(response.status)
    return response.json()
    }).then((myJson) => {
    console.log(myJson)
    }).catch((error) => {
    console.log(`錯誤代碼為${error}`)
    })

    框架

    jQuery

    jQuery

    Axios(推薦)

    Axios

    參考

    XMLHttpRequest — JavaScript 發送 HTTP 請求 (I)
    網頁開發人員應了解的 HTTP 狀態碼
    練習用APIList