Ajax 與 Axios 非同步請求

来源:https://www.cnblogs.com/cs-songbai/p/18102073
-Advertisement-
Play Games

Ajax 與 Axios 非同步請求 一、伺服器對外提供了哪些資源 1. 網頁中如何請求數據 數據,也是伺服器對外提供的一種資源。只要是資源,必然要通過 請求 – 處理 – 響應 的方式進行獲取。如果要在網頁中請求伺服器上的數據資源,則需要用到 XMLHttpRequest 對象。XMLHttpReq ...


Ajax 與 Axios 非同步請求

一、伺服器對外提供了哪些資源

1. 網頁中如何請求數據

	數據,也是伺服器對外提供的一種資源。只要是資源,必然要通過 請求 – 處理 – 響應 的方式進行獲取。如果要在網頁中請求伺服器上的數據資源,則需要用到 XMLHttpRequest 對象。XMLHttpRequest(簡稱 xhr)是瀏覽器提供的 js 成員,通過它,可以請求伺服器上的數據資源。最簡單的用法 var xhrObj = new XMLHttpRequest()

2. 資源的請求方式

客戶端請求伺服器時,請求的方式有很多種,最常見的兩種請求方式分別為 get 和 post 請求。

  • get 請求通常用於獲取服務端資源(向伺服器要資源)

    例如:根據 URL 地址,從伺服器獲取 HTML 文件、css 文件、js文件、圖片文件、數據資源等
    
  • post 請求通常用於向伺服器提交數據(往伺服器發送資源)

    例如:登錄時向伺服器提交的登錄信息、註冊時向伺服器提交的註冊信息、添加用戶時向伺服器提交的用戶信息等各種數據提交操作
    

二、Ajax 非同步請求

1. 什麼是Ajax

	Ajax 的全稱是 Asynchronous Javascript And XML(非同步 JavaScript 和 XML)。通俗的理解:在網頁中利用 XMLHttpRequest 對象和伺服器進行數據交互的方式,就是Ajax。
	瀏覽器中提供的 XMLHttpRequest 用法比較複雜,所以 jQuery 對 XMLHttpRequest 進行了封裝,提供了一系列 Ajax 相關的函數,極大地降低了 Ajax 的使用難度

2. 為什麼要學Ajax

	之前所學的技術,只能把網頁做的更美觀漂亮,或添加一些動畫效果,但是,Ajax能讓我們輕鬆實現網頁與伺服器之間的數據交互。

3. Ajax的典型應用場景

  • 用戶名檢測:註冊用戶時,通過 ajax 的形式,動態檢測用戶名是否被占用
  • 搜索提示:當輸入搜索關鍵字時,通過 ajax 的形式,動態載入搜索提示列表
  • 數據分頁顯示:當點擊頁碼值的時候,通過 ajax 的形式,根據頁碼值動態刷新表格的數據
  • 數據的增刪改查:數據的添加、刪除、修改、查詢操作,都需要通過 ajax 的形式,來實現數據的交互

4. Ajax 的應用

  • jQuery 中發起 Ajax 請求最常用的三個方法
    // get請求
    $.get()
    // post請求
    $.post()
    // 通用請求
    $.ajax()
    
  • $.get()函數的語法
    jQuery 中 $.get() 函數的功能單一,專門用來發起 get 請求,從而將伺服器上的資源請求到客戶端來進行使用。$.get() 函數的語法如下:
    
    • $.get() 函數的語法如下:

      $.get(url, [data], [callback])
      
    • 其中,三個參數各自代表的含義如下:

      參數名 參數類型 是否必選 說明
      url string 要請求的資源地址
      data object 請求資源期間要攜帶的參數
      callback function 請求成功時的回調函數
    • $.get()發起不帶參數的請求

      // 使用 $.get() 函數發起不帶參數的請求時,直接提供請求的 URL 地址和請求成功之後的回調函數即可:
      $.get("http://ajax-base-api-t.itheima.net/api/getbooks", function(res) {
          console.log(res) // 這裡的 res 是伺服器返回的數據
      })
      
    • $.get()發起帶參數的請求

      // 使用 $.get() 函數發起帶參數的請求時,示例代碼如下:
      $.get("http://ajax-base-api-t.itheima.net/api/getbooks", { id: 1 }, function(res) {
        console.log(res)
      })
      
  • $.post()函數的語法
    jQuery 中 $.post() 函數的功能單一,專門用來發起 post 請求,從而向伺服器提交數據。
    
    • $.post() 函數的語法如下:

      $.post(url, [data], [callback])
      
    • 其中,三個參數各自代表的含義如下:

      參數名 參數類型 是否必選 說明
      url string 提交數據的地址
      data object 要提交的數據
      callback function 數據提交成功時的回調函數
    • $.post()向伺服器提交數據

      // 使用 $post() 向伺服器提交數據的示例代碼如下:
      $.post(
         "http://ajax-base-api-t.itheima.net/api/addbook", // 請求的URL地址
         { bookname: '水滸傳', author: '施耐庵', publisher: '上海圖書出版社' }, // 提交的數據
         function(res) { // 回調函數
            console.log(res)
         }
      )
      
  • $.ajax()函數的語法
    相比於 $.get() 和 $.post() 函數,jQuery 中提供的 $.ajax() 函數,是一個功能比較綜合的函數,它允許我們對 Ajax 請求進行更詳細的配置。
    
    • $.ajax() 函數的基本語法如下:

      $.ajax({
         type: '', // 請求的方式,例如 GET 或 POST
         url: '',  // 請求的 URL 地址
         data: { },// 這次請求要攜帶的數據
         success: function(res) { } // 請求成功之後的回調函數
      })
      
    • 使用$.ajax()發起GET請求

      // 使用 $.ajax() 發起 GET 請求時,只需要將 type 屬性的值設置為 'GET' 即可:
      $.ajax({
         type: 'GET', // 請求的方式
         url: "http://ajax-base-api-t.itheima.net/api/getbooks",  // 請求的 URL 地址
         data: { id: 1 },// 這次請求要攜帶的數據
         success: function(res) { // 請求成功之後的回調函數
             console.log(res)
         }
      })
      
      • GET請求實戰案例前後端交互

        • 前端代碼

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>加法運算</title>
              <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
          </head>
          <body>
              <div>
                  <h3>ajax GET請求頁面</h3>
                  <input type="text"> +
                  <input type="text"> =
                  <input type="text">
                  <input type="button" value="計算">
              </div>
              <script>
                  let nums = $("input[type='text']");
                  let btn = $("input[type='button']");
          
                  btn.click(function (){
                      // 發起get請求: http://127.0.0.1:8888/calc?num1=1.3&num2=3.6
                      $.ajax({
                          url:"/calc",
                          type:"get",
                          dataType:"json",
                          data:{
                              "num1": Number(nums.eq(0).val()),
                              "num2": Number(nums.eq(1).val())
                          },
                          success:function (response) {
                              console.log("響應數據:",response);
                              console.log("響應數據類型:",typeof(response));
                              nums.eq(2).val(response["result"]);
                          },
                          error:function (error) {
                              console.log(error.readyState);
                              console.log(error.status);
                              console.log(error.statusText);
                              console.log(error.responseText);
                          }
                      })
                  })
              </script>
          </body>
          </html>
          
        • 後端代碼

          import tornado.web
          import tornado.ioloop
          
          
          class MainHandler(tornado.web.RequestHandler):
          
              def get(self):
                  self.render("calc_get.html")
          
          
          class ReferHandler(tornado.web.RequestHandler):
              def get(self):
                  # print("請求頭信息\n:", self.request.headers)
                  print("請求url: ", self.request.full_url())
                  # 獲取原始查詢參數和請求體參數
                  print("查詢參數:", self.request.arguments)
                  print("請求體參數:", self.request.body)
          
                  # 框架解析之後的數據, 如果原始查詢參數無數據則報錯
                  num1 = self.get_argument("num1")
                  num2 = self.get_argument("num2")
                  # 通過url以鍵值對形式傳參解析出來的數據均為字元串格式
                  print("接收的查詢參數num1類型為", type(num1))
                  print("接收的查詢參數num1, num2值為", num1, num2)
                  result = round(float(num1) + float(num2), 4)
          
                  # .write會檢測參數,將字典轉為json數據以後返回
                  self.write({"result": result})
          
          
          if __name__ == '__main__':
              app = tornado.web.Application([
                  ("/", MainHandler),
                  ("/calc", ReferHandler),
              ])
          
              app.listen(8888)
              tornado.ioloop.IOLoop.current().start()
          
          
    • 使用$.ajax()發起POST請求

      // 使用 $.ajax() 發起 POST 請求時,只需要將 type 屬性的值設置為 'POST' 即可:
      $.ajax({
         type: 'POST', // 請求的方式
         url: "http://ajax-base-api-t.itheima.net/api/addbook",  // 請求的 URL 地址
         data: { // 要提交給伺服器的數據
            bookname: '水滸傳',
            author: '施耐庵',
            publisher: '上海圖書出版社'
          },
         success: function(res) { // 請求成功之後的回調函數
             console.log(res)
         }
      })
      
      • POST請求實戰案例前後端交互

        • 前端代碼

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>加法運算</title>
              <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
          </head>
          <body>
              <div>
                  <h3>ajax POST請求頁面</h3>
                  <input type="text"> +
                  <input type="text"> =
                  <input type="text">
                  <input type="button" value="計算">
              </div>
              <script>
                  let nums = $("input[type='text']");
                  let btn = $("input[type='button']");
          
                  btn.click(function (){
                      // 發起post請求: http://127.0.0.1:8888
                      $.ajax({
                          url:"/",
                          type:"post",
                          // post請求一般會指定發送給伺服器的數據格式
                          contentType:"application/json",
                          dataType:"json",
                          // 將數據轉換為json格式發送
                          data:JSON.stringify({
                              "num1": Number(nums.eq(0).val()),
                              "num2": Number(nums.eq(1).val())
                          }),
                          success:function (response) {
                              console.log("響應數據:",response);
                              console.log("響應數據類型:",typeof(response));
                              nums.eq(2).val(response["result"]);
                          },
                          error:function (error) {
                              console.log(error.readyState);
                              console.log(error.status);
                              console.log(error.statusText);
                              console.log(error.responseText);
                          }
                      })
                  })
              </script>
          </body>
          </html>
          
        • 後端代碼

          import json
          
          import tornado.web
          import tornado.ioloop
          
          
          class MainHandler(tornado.web.RequestHandler):
          
              def get(self):
                  self.render("calc_post.html")
          
              def post(self):
                  # print("請求頭信息\n:", self.request.headers)
                  print("請求url: ", self.request.full_url())
                  # 獲取原始查詢參數和請求體參數
                  print("查詢參數:", self.request.arguments)
                  print("請求體參數:", self.request.body)
          
                  # 框架解析之後的數據
                  data = json.loads(self.request.body)
                  num1 = data["num1"]
                  num2 = data["num2"]
                  print("接收的請求體參數num1類型為", type(num1))
                  print("接收的請求體參數num1, num2值為", num1, num2)
                  result = round(num1 + num2, 4)
          
                  # .write會檢測參數,將字典轉為json數據以後返回
                  self.write({"result": result})
          
          
          if __name__ == '__main__':
              app = tornado.web.Application([
                  ("/", MainHandler),
              ])
          
              app.listen(8888)
              tornado.ioloop.IOLoop.current().start()
          
          
    • ajax非同步請求參數說明

      【contentType】: 發送給伺服器的數據格式; 可選4種格式:
          1> application/x-www-form-urlencoded: 預設方式,在請求發送過程中會對數據進行序列化處理,以鍵值對形式 ?key1=value1&key2=value的方式發送到伺服器
          2> multipart/form-data: 需要在表單中進行文件上傳時,就需要使用該格式
          3> application/json: 消息主體是序列化後的 JSON 字元串
          4> text/plain: 數據以純文本形式(text/json/xml/html)進行編碼,其中不含任何控制項或格式字元
      
          eg:
              contentType:"application/json",
      
      【dataType】: 用什麼格式解析服務端響應的數據(並非是原生ajax的屬性),有些框架(比如jquery)預設(未填寫dataType或解析錯誤的情況下)讀取服務端的響應頭Content-Type
          1> text:預設值。預期數據為純文本字元串。
          2> html:預期數據為html格式的字元串。
          3> json:預期數據為JSON格式的對象或數組。
          4> xml:預期數據為XML文檔類型的數據。
      
          說明: 指定dataType參數後,如果返回的數據類型與預期不符合,則ajax請求會失敗,並觸發error回調函數。因此,正確指定dataType參數對於確保ajax請求的數據類型是非常重要的。
      
      【jquery ajax 出錯信息解讀-error屬性值】
          1> readyState :當前狀態,0-未初始化,1-正在載入,2-已經載入,3-數據進行交互,4-完成。
          2> status :返回的HTTP狀態碼,比如常見的404,500等錯誤代碼。
          3> statusText :對應狀態碼的錯誤信息,比如404錯誤信息是not found,500是Internal Server Error。
          4> responseText :伺服器響應返回的文本信息
      

三、 Axios 非同步請求

1. 什麼是axios

Axios 是基於Promise的HTTP客戶端作用於瀏覽器和node.js,專註於網路數據請求的庫。相比於原生的 XMLHttpRequest 對象,axios 簡單易用。相比於 jQuery,axios 更加輕量化,只專註於網路數據請求。

2. axios 的應用

  • axios 發起GET請求
    • axios 發起 get 請求的語法:

      axios.get('url', { params: { /*參數*/ } }).then(callback)
      
    • 具體的請求示例如下:

       // 請求的 URL 地址
       var url = 'http://ajax-base-api-t.itheima.net/api/get'
       // 請求的參數對象
       var paramsObj = { name: 'zs', age: 20 }
       // 調用 axios.get() 發起 GET 請求
       axios.get(url, { params: paramsObj }).then(function(res) {
           // res.data 是伺服器返回的數據
           var result = res.data
           console.log(res)
       })
      
  • axios發起POST請求
    • axios 發起 post 請求的語法:

      axios.post('url', { /*參數*/ }).then(callback)
      
    • 具體的請求示例如下:

       // 請求的 URL 地址
       var url = 'http://ajax-base-api-t.itheima.net/api/post'
       // 要提交到伺服器的數據
       var dataObj = { location: '北京', address: '順義' }
       // 調用 axios.post() 發起 POST 請求
       axios.post(url, dataObj).then(function(res) {
           // res.data 是伺服器返回的數據
           var result = res.data
           console.log(result)
       })
      
  • 直接使用axios發起請求
    • 直接使用axios發起請求 ,axios 也提供了類似於jQuery$.ajax() 的函數,語法如下:

       axios({
           method: '請求類型',
           url: '請求的URL地址',
           data: { /* POST數據 */ },
           params: { /* GET參數 */ }
       }) .then(callback)
      
    • 直接使用axios發起GET請求

         
       axios({
           method: 'GET',
           url: 'http://www.liulongbin.top:3006/api/get',
           params: { // GET 參數要通過 params 屬性提供
               name: 'zs',
               age: 20
           }
       }).then(function(res) {
           console.log(res.data)
       })
      
      
    • 直接使用axios發起POST請求

      axios({
           method: 'POST',
           url: 'http://www.liulongbin.top:3006/api/post',
           data: { // POST 數據要通過 data 屬性提供
               bookname: '程式員的自我修養',
               price: 666
           }
       }).then(function(res) {
           console.log(res.data)
       })
      

四、 介面

  • 介面的概念

    使用 Ajax 請求數據時,被請求的 URL 地址,就叫做數據介面(簡稱介面)。同時,每個介面必須有請求方式。
    
    例如:
    	http://ajax-base-api-t.itheima.net/api/getbooks  獲取圖書列表的介面(GET請求)
    	http://ajax-base-api-t.itheima.net/api/addbook   添加圖書的介面(POST請求)
    
  • 介面的請求過程

  • 介面文檔

    • 什麼是介面文檔

      介面文檔,顧名思義就是介面的說明文檔,它是我們調用介面的依據。好的介面文檔包含了對介面URL,參數以及輸出內容的說明,我們參照介面文檔就能方便的知道介面的作用,以及介面如何進行調用。
      
    • 介面文檔的組成部分

      介面文檔可以包含很多信息,也可以按需進行精簡,不過,一個合格的介面文檔,應該包含以下6項內容,從而為介面的調用提供依據:
      
      • 介面名稱:用來標識各個介面的簡單說明,如登錄介面,獲取圖書列表介面等。
      • 介面URL:介面的調用地址
      • 調用方式:介面的調用方式,如 GET 或 POST
      • 參數格式:介面需要傳遞的參數,每個參數必須包含參數名稱、參數類型、是否必選、參數說明這4項內容
      • 響應格式:介面的返回值的詳細描述,一般包含數據名稱、數據類型、說明3項內容。
      • 返回示例(可選):通過對象的形式,例舉伺服器返回數據的結構。
    • 介面文檔示例

      • 圖書列表

        • 介面URL /api/getbooks

        • 調用方式: GET

        • 參數格式 - PTND

          參數名稱(params) 參數類型(type) 是否必選(necessary) 參數說明(description)
          id Number 圖書Id
          bookname String 圖書名稱
          author String 作者
          publisher String 出版社
        • 響應格式 - PTD

          數據名稱 數據類型 說明
          status Number 200 成功;500 失敗;
          msg String 對 status 欄位的詳細說明
          data Array 圖書列表
          +id Number 圖書Id
          +bookname String 圖書名稱
          +author String 作者
          +publisher String 出版社
        • 返回示例

          {
            "status": 200,
            "msg": "獲取圖書列表成功",
            "data": [
              { "id": 1, "bookname": "西游記", "author": "吳承恩", "publisher": "北京圖書出版社" },
              { "id": 2, "bookname": "紅樓夢", "author": "曹雪芹", "publisher": "上海圖書出版社" },
              { "id": 3, "bookname": "三國演義", "author": "羅貫中", "publisher": "北京圖書出版社" }
            ]
          }
          

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 遍歷是指通過或遍歷節點樹 遍歷節點樹 通常,您想要迴圈一個 XML 文檔,例如:當您想要提取每個元素的值時。 這被稱為"遍歷節點樹"。 下麵的示例迴圈遍歷所有 <book> 的子節點,並顯示它們的名稱和值: <!DOCTYPE html> <html> <body> <p id="demo"></p ...
  • 一、是什麼 HTTP頭欄位(HTTP header fields),是指在超文本傳輸協議(HTTP)的請求和響應消息中的消息頭部分 它們定義了一個超文本傳輸協議事務中的操作參數 HTTP頭部欄位可以自己根據需要定義,因此可能在 Web伺服器和瀏覽器上發現非標準的頭欄位 下麵是一個HTTP請求的請求頭 ...
  • DOM(文檔對象模型)定義了一種訪問和操作文檔的標準。它是一個平臺和語言無關的介面,允許程式和腳本動態訪問和更新文檔的內容、結構和樣式。HTML DOM用於操作HTML文檔,而XML DOM用於操作XML文檔。 HTML DOM示例 通過ID獲取並修改HTML元素的值: <!DOCTYPE html ...
  • 一、是什麼 HTTP狀態碼(英語:HTTP Status Code),用以表示網頁伺服器超文本傳輸協議響應狀態的3位數字代碼 它由 RFC 2616規範定義的,並得到 RFC 2518、RFC 2817、RFC 2295、RFC 2774與 RFC 4918等規範擴展 簡單來講,http狀態碼的作用 ...
  • 1.簡介 開源 Web 富文本編輯器,開箱即用,配置簡單。一個產品的價值,就在於解決用戶的問題,提高效率、降低成本、增加穩定性和擴展性。wangEditor 不是為了做而做,也不是單純的模仿誰,而是經過上述問題分析之後,給出一個系統的解決方案。旨在真正去解決用戶的問題,產出自己的價值。更多資料見官網 ...
  • 1.需求描述 根據項目需求,採用Antd組件庫需要封裝一個評論框,具有以下功能: 支持文字輸入 支持常用表情包選擇 支持發佈評論 支持自定義表情包 2.封裝代碼 ./InputComment.tsx 1 import React, { useState, useRef, useEffect, for ...
  • 需要實現的效果: 1、子菜單如果不是全部選中,一級菜單半選。 2、子菜單全選,一級菜單選中。 3、一級菜單選擇,二級菜單全選。 4、沒有二級菜單,則只控制一級菜單。 主要用到的屬性是checked和halfCheckedKeys,通過手動控制那些菜單選中,那些半選中實現功能。 **頁面截圖: ** ...
  • 一、HTTP1.0 HTTP協議的第二個版本,第一個在通訊中指定版本號的HTTP協議版本 HTTP 1.0 瀏覽器與伺服器只保持短暫的連接,每次請求都需要與伺服器建立一個TCP連接 伺服器完成請求處理後立即斷開TCP連接,伺服器不跟蹤每個客戶也不記錄過去的請求 簡單來講,每次與伺服器交互,都需要新開 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...