wordpress_blog

This is a dynamic to static website.

JavaScript 複習08

AJAX – 網路請求

什麼是 AJAX? 它如何改善網頁使用體驗?

// AJAX
// Asynchronous JavaScript and XML
// 非同步的 JavaScript 與 XML 技術

什麼是網路請求?

// 網路請求
/*
  透過 Chrome 執行 Enter URL 動作,
  我傳送了一個網路請求,
  取得: get URL 網頁上的資訊
*/
// 其他軟體也可以發出網路請求
// 透過 JS 發出網路請求

從網頁架構瞭解網頁請求 – 上集

// index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Review JS</title>

</head>
<body>
  
  <h1>複習 Review JS</h1>
  <ul class="list"></ul>
  <img src="img.jpg" alt="">

  <script src="all.js"></script>
</body>
</html>
// 開啟 Network 方法,查出有幾個網路請求
// 方法一
// Chrome 瀏覽器 > 滑鼠右鍵檢查 > Network
// 方法二
// 自訂及管理 Google Chrome > 更多工具 > 開發人員工具 > Network

從網頁架構瞭解網頁請求 – 下集

// index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Review JS</title>

</head>
<body>
  
  <h1>複習 Review JS</h1>
  <ul class="list"></ul>
  <img src="image.jpg" alt="">

  <script src="all.js"></script>
</body>
</html>
// 從網頁架構瞭解網頁請求 - 下集
// Chrome 瀏覽器輸入網址按下 Enter 後,就會發送 get 請求到伺服器上
// 再經由伺服器回傳資料給 Chrome 瀏覽器
// 1. index.html
// 2. img
// 3. all.js
// 瀏覽器解析到圖片時,會去跟本地端伺服器請求圖片檔案
// 網路請求有先後順序,並不是一次全部請求

網頁請求狀態碼

// HTTP 狀態碼
// 網頁請求狀態碼
// HTTP 狀態碼
// 1. 資訊回應 (Informational responses, 100 - 199)
// 2. 成功回應 (Successful responses, 200 - 299)
// 3. 重定向 (Redirects, 300 - 399)
// 4. 用戶端錯誤 (Client errors, 400 - 499)
// 5. 伺服器端錯誤 (Server errors, 500 - 599)
// 常見的網頁請求狀態碼
// 404 Not Found - 伺服器找不到請求的資源
// 200 OK - 請求成功
// 304 Not Modified - 無需再次傳輸請求的內容
// 500 Internal Server Error - 伺服器端發生未知或無法處理的錯誤
// 清除快取並強制重新載入 (開發人員工具要打開)
// 方法一
// 重新整理圖示長按左鍵後選取清除快取並強制重新載入
// 方法二
// 重新整理圖示右鍵後選取清除快取並強制重新載入

request、response 講解

// request、response 講解
// request(請求): 傳送給伺服器要什麼資料
// 瀏覽器 → request(請求) → 伺服器
// response(回傳): 回傳給瀏覽器資料
// 瀏覽器 ← response(回傳) ← 伺服器
// response header (Headers > Response Headers)
// response data (Response)


// Chrome > Network > Name - index.html > Headers > Request Headers

用 Node.js 開啟伺服器,更加瞭解 request、response 的差異

// Chrome → request → Node.js 後端伺服器
// Chrome ← response ← Node.js 後端伺服器

// 使用終端機用 Node.js 開啟伺服器
// node app.js
// app.js - 1
const http = require("http");

http.createServer(function(request, response) {
  console.log(request);
  if (request.url == "/") {
    console.log("接收到網頁請求!");
    response.writeHead(200, { "Content-Type": "text/HTML" });
    response.write("<h1>index</h1>");
    response.end();
  }

}).listen(process.env.PORT || 3000);
console.log("Server已開啟port: 3000.");
// app.js - 2
const http = require("http");

http.createServer(function(request, response) {
  console.log(request.url);
  if (request.url == "/") {
    console.log("接收到網頁請求!");
    response.writeHead(200, { "Content-Type": "text/HTML" });
    response.write("<h1>index</h1>");
    response.end();
  } else {
    console.log("接收到網頁請求!");
    response.writeHead(200, { "Content-Type": "text/HTML" });
    response.write("<h1>not index</h1>");
    response.end();
  }

}).listen(process.env.PORT || 3000);
console.log("Server已開啟port: 3000.");

AJAX – axios 套件教學

各種發出網路請求的 JS 寫法種類介紹

// JavaScript 原生寫法
// 1. XMLHttpRequest
// 2. Fetch

// 套件,無須額外載入 JS
// axios
// 使用 XMLHttpRequest
function reqListener() {
  console.log(this.responseText);
}

var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.example.org/example.txt");
oReq.send();
// Using the Fetch API
fetch("http://example.com/movies.json")
  .then(function (response) {
    return response.json();
  })
  .then(function (myJson) {
    console.log(myJson);
  });

axios 環境安裝

// index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Review JS</title>
</head>
<body>
  
  <h1>複習 Review JS</h1>

  <script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
  <script src="all.js"></script>
</body>
</html>
// all.js
// 套件 CDN 程式碼與自己撰寫載入的程式碼載入順序有差
// 套件程式碼載入放在自己撰寫的程式碼之前

// 檢查套件載入有沒有成功
// 方法一
// 使用 Chrome Network 查看 Status Code
// 方法二
// 使用 Console 查看
console.log(axios);

axios – 嘗試串接外部資料

// all.js
// https://hexschool.github.io/ajaxHomework/data.json

axios.get('https://hexschool.github.io/ajaxHomework/data.json')
  .then(function (response) {
    console.log(response.data);
    console.log(response.status);
    console.log(response.statusText);
    console.log(response.headers);
    console.log(response.config);
  });

axios – response 參數詳細講解

// all.js
// When using then, you will receive the response as follows:
axios.get('https://hexschool.github.io/ajaxHomework/data.json')
  .then(function (response) {
    // response 為物件格式
    console.log(response);

    console.log(response.data);
    console.log(response.status);
    console.log(response.statusText);
    console.log(response.headers);
    console.log(response.config);
  });

axios – 將外部資料寫入到網頁上

// index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Review JS</title>

</head>
<body>
  
  <h1>複習 Review JS</h1>
  <h2 class="title"></h2>

  <script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
  <script src="all.js"></script>
</body>
</html>
// all.js

axios.get('https://hexschool.github.io/ajaxHomework/data.json')
  .then(function (response) {
    let ary = response.data;
    console.log(ary[0].name);

    const title = document.querySelector(".title");
    title.textContent = ary[0].name;

  });

axios – 非同步觀念

// all.js
let ary = [];

// 非同步 AJAX 觀念
// 透過 AJAX 方法發送 get 請求,當資料還沒回傳時,程式碼還是會繼續往下執行
axios.get('https://hexschool.github.io/ajaxHomework/data.json')
  .then(function (response) {
    console.log("資料有回傳了");  // 1. 資料有回傳了

    ary = response.data;
    console.log(ary);  // 2. [{...}]

  });
  
console.log(ary);  // 3. []


// 執行順序
// 3 > 1 > 2

透過函式設計處理非同步

// all.js
let ary = [];

axios.get('https://hexschool.github.io/ajaxHomework/data.json')
  .then(function (response) {
    console.log("資料有回傳了");  // 1. 資料有回傳了
    ary = response.data; 
    renderData();
  });

// 資料渲染
// 資料回傳後,再執行函式
function renderData() {
  console.log(ary);  // 2. [{...}]
  const title = document.querySelector(".title");
  title.textContent = ary[0].name;
}
  
console.log(ary);  // 3. []

// 執行順序
// 3 > 1 > 2

AJAX POST API 講解

網路請求種類介紹

post 網路請求文件介紹

// readme.md
// 六角學院 AJAX 練習
// 注意,此範例僅供練習,並不會儲存用戶資料置資料庫(僅緩存)。

// 註冊
// 新增一個帳號。
// Method: POST
// URL: https://hex-escape-room.herokuapp.com/api/user/signup
// Data:
// {
//   email: 'lovef2e@hexschool.com',
//   password: '12345678'
// }
// Success Response:
// {
//   "success": true,
//   "result": {},
//   "message": "帳號註冊成功"
// }
// Error Response:
// {
//   "success": false,
//   "result": {},
//   "message": "此帳號已被使用"
// }

// 登入
// 登入一個已存在的帳號。
// Method: POST
// URL: https://hex-escape-room.herokuapp.com/api/user/signin
// Data:
// {
//   email: 'lovef2e@hexschool.com',
//   password: '12345678'
// }
// Success Response:
// {
//   "success": true,
//   "result": {},
//   "message": "登入成功"
// }
// Error Response:
// {
//   "success": false,
//   "result": {},
//   "message": "此帳號不存在或帳號密碼錯誤"
// }

四種常見的 POST 請求 content-type 介紹

// all.js
// 常見請求資料格式 request header Content-Type
// 1. application/x-www-form-urlencoded
// 2. application/json
// 3. multipart/form-data
// 4. text/plain (記事本格式最少使用)

// axios 預設屬於第2種請求資料格式,支援其他格式,可以自己設定
// multipart/form-data: 傳送檔案格式的時候,檔案: 圖片、pdf、word、mp4
// application/x-www-form-urlencoded: 是屬於 <form> 表單的原生提交方式

透過 axios 實驗註冊 post 網路請求

// axios post 範例
axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Review JS</title>

</head>
<body>
  
  <h1>複習 Review JS</h1>

  <script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
  <script src="all.js"></script>
</body>
</html>
// all.js - 第二個參數是資料的物件格式 - 方式一
// url
// https://hex-escape-room.herokuapp.com/api/user/signup

axios.post('https://hex-escape-room.herokuapp.com/api/user/signup', {
  email: 'geehsu@hexschool.com',
  password: '12345678'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
// all.js - 第二個參數是資料的物件格式 - 方式二
// url
// https://hex-escape-room.herokuapp.com/api/user/signup

let obj = {
  email: 'geehsu@hexschool.com',
  password: '12345678'
};

axios.post('https://hex-escape-room.herokuapp.com/api/user/signup', obj)
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

從 chrome 觀察 post 請求

// all.js
// 講解關於 Chrome 瀏覽器的底層運作
/*
透過瀏覽器開發人員工具除錯
Chrome Network > signup > Header, Payload, Response
Chrome Console
*/

// url
// https://hex-escape-room.herokuapp.com/api/user/signup

function callSignUp() {
  let obj = {
    email: "geehsu@hexschool.com",
    password: "12345678",
  };

  axios
    .post("https://hex-escape-room.herokuapp.com/api/user/signup", obj)
    .then(function (response) {
      console.log(response.data);
    })
    .catch(function (error) {
      console.log(error);
    });
}

實作 axios DOM 表單註冊流程

// index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Review JS</title>

  </head>
  <body>
    <h1>複習 Review JS</h1>
    <label for="">帳號:</label>
    <input type="text" class="account" />
    <br />
    <label for="">密碼:</label>
    <input type="text" class="password" />
    <br /><br />
    <input type="button" value="送出" class="send" />

    <script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
    <script src="all.js"></script>
  </body>
</html>
// all.js
// url
// https://hex-escape-room.herokuapp.com/api/user/signup

const account = document.querySelector(".account");
const password = document.querySelector(".password");
const send = document.querySelector(".send");

// console.log(account, password, send);

send.addEventListener("click", function (e) {
  // console.log("是否被點擊");
  callSignUp();
});

function callSignUp() {
  if (account.value == "" || password.value == "") {
    alert("請填寫正確資訊");
    return;
  }

  let obj = {};
  obj.email = account.value;
  obj.password = password.value;
  // console.log(obj);

  axios
    .post("https://hex-escape-room.herokuapp.com/api/user/signup", obj)
    .then(function (response) {
      // console.log(response.data);
      // alert(response.data.message);
      if (response.data.message == "帳號註冊成功") {
        alert("恭喜帳號註冊成功");
      } else {
        alert("帳號註冊失敗,有可能有人用你的email註冊!");
      }
      account.value = "";
      password.value = "";
    })
    .catch(function (error) {
      console.log(error);
    });
}

AJAX POST 小節作業

// index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Review JS</title>

  </head>
  <body>
    <h1>複習 Review JS</h1>
    <h2>註冊功能</h2>
    <label for="">帳號:</label>
    <input type="text" class="signupAccount" />
    <br />
    <label for="">密碼:</label>
    <input type="text" class="signupPassword" />
    <br /><br />
    <input type="button" value="送出" class="signupSend" />
    <h2>登入功能</h2>
    <label for="">帳號:</label>
    <input type="text" class="loginAccount" />
    <br />
    <label for="">密碼:</label>
    <input type="text" class="loginPassword" />
    <br /><br />
    <input type="button" value="送出" class="loginSend" />

    <script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
    <script src="all.js"></script>
  </body>
</html>
// all.js
// url
// signup
// https://hex-escape-room.herokuapp.com/api/user/signup
// signin / login
// https://hex-escape-room.herokuapp.com/api/user/signin

// 1.註冊功能
// 2.登入功能

// 宣告變數綁定 DOM 元素
const signupAccount = document.querySelector(".signupAccount");
const signupPassword = document.querySelector(".signupPassword");
const signupSend = document.querySelector(".signupSend");

// 事件監聽 click 按鈕
signupSend.addEventListener("click", function (e) {
  console.log("觸發點擊事件!");
  // 執行函式
  callSignup();
});

// 宣告函式執行註冊功能
function callSignup() {
  console.log("執行註冊功能");

  if (signupAccount.value == "" || signupPassword.value == "") {
    alert("請填寫正確內容");
    // 回傳然後結束
    return;
  }

  let obj = {};
  obj.email = signupAccount.value;
  obj.password = signupPassword.value;
  console.log(obj);

  // axios 套件 post 方法
  axios
    .post("https://hex-escape-room.herokuapp.com/api/user/signup", obj)
    .then(function (response) {
      console.log(response);
      console.log(response.data);
      console.log(response.data.message);

      // 流程判斷
      if (response.data.message == "帳號註冊成功") {
        console.log("已成功註冊帳號!");
        alert("已經成功註冊帳號!");
      } else {
        console.log("已有人註冊此email");
        alert("已有人註冊此email");
      }

      signupAccount.value = "";
      signupPassword.value = "";
    })
    .catch(function (error) {
      console.log(error);
    });
}

const loginAccount = document.querySelector(".loginAccount");
const loginPassword = document.querySelector(".loginPassword");
const loginSend = document.querySelector(".loginSend");

loginSend.addEventListener("click", function (e) {
  console.log("觸發點擊事件");
  callLogin();
});

function callLogin() {
  console.log("執行登入功能");

  if (loginAccount.value == "" || loginPassword.value == "") {
    alert("請填寫正確內容");
    return;
  }

  let obj = {};
  obj.email = loginAccount.value;
  obj.password = loginPassword.value;
  console.log(obj);

  axios
    .post("https://hex-escape-room.herokuapp.com/api/user/signin", obj)
    .then(function (response) {
      console.log(response);
      console.log(response.data.message);

      if (response.data.message == "登入成功") {
        alert("登入成功");
      } else if (response.data.message == "此帳號不存在或帳號密碼錯誤") {
        alert("此帳號不存在或帳號密碼錯誤");
      }

      loginAccount.value = "";
      loginPassword.value = "";
    })
    .catch(function (error) {
      console.log(error);
    });
}