Java 208 道面試題 · (八)網路

_沈發表於2020-12-14

Java 208 道面試題 · (八)網路

79. http 響應碼 301 和 302 代表的是什麼?有什麼區別?

答:301,302 都是HTTP狀態的編碼,都代表著某個URL發生了轉移。

區別:

  • 301 redirect: 301 代表永久性轉移(Permanently Moved)。
  • 302 redirect: 302 代表暫時性轉移(Temporarily Moved )。

80. forward 和 redirect 的區別?

Forward和Redirect代表了兩種請求轉發方式:直接轉發和間接轉發。

直接轉發方式(Forward),客戶端和瀏覽器只發出一次請求,Servlet、HTML、JSP或其它資訊資源,由第二個資訊資源響應該請求,在請求物件request中,儲存的物件對於每個資訊資源是共享的。

間接轉發方式(Redirect)實際是兩次HTTP請求,伺服器端在響應第一次請求的時候,讓瀏覽器再向另外一個URL發出請求,從而達到轉發的目的。

舉個通俗的例子:

直接轉發就相當於:“A找B借錢,B說沒有,B去找C借,借到借不到都會把訊息傳遞給A”;

間接轉發就相當於:“A找B借錢,B說沒有,讓A去找C借”。

81. 簡述 tcp 和 udp的區別?

  • TCP面向連線(如打電話要先撥號建立連線);UDP是無連線的,即傳送資料之前不需要建立連線。
  • CP提供可靠的服務。也就是說,通過TCP連線傳送的資料,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付。
  • cp通過校驗和,重傳控制,序號標識,滑動視窗、確認應答實現可靠傳輸。如丟包時的重發控制,還可以對次序亂掉的分包進行順序控制。
  • UDP具有較好的實時性,工作效率比TCP高,適用於對高速傳輸和實時性有較高的通訊或廣播通訊。
  • 每一條TCP連線只能是點到點的;UDP支援一對一,一對多,多對一和多對多的互動通訊。
  • TCP對系統資源要求較多,UDP對系統資源要求較少。

82. tcp 為什麼要三次握手,兩次不行嗎?為什麼?

為了實現可靠資料傳輸, TCP 協議的通訊雙方, 都必須維護一個序列號, 以標識傳送出去的資料包中, 哪些是已經被對方收到的。 三次握手的過程即是通訊雙方相互告知序列號起始值, 並確認對方已經收到了序列號起始值的必經步驟。

如果只是兩次握手, 至多隻有連線發起方的起始序列號能被確認, 另一方選擇的序列號則得不到確認。

83. 說一下 tcp 粘包是怎麼產生的?

①. 傳送方產生粘包

採用TCP協議傳輸資料的客戶端與伺服器經常是保持一個長連線的狀態(一次連線發一次資料不存在粘包),雙方在連線不斷開的情況下,可以一直傳輸資料;但當傳送的資料包過於的小時,那麼TCP協議預設的會啟用Nagle演算法,將這些較小的資料包進行合併傳送(緩衝區資料傳送是一個堆壓的過程);這個合併過程就是在傳送緩衝區中進行的,也就是說資料傳送出來它已經是粘包的狀態了。

在這裡插入圖片描述
②. 接收方產生粘包

接收方採用TCP協議接收資料時的過程是這樣的:資料到底接收方,從網路模型的下方傳遞至傳輸層,傳輸層的TCP協議處理是將其放置接收緩衝區,然後由應用層來主動獲取(C語言用recv、read等函式);這時會出現一個問題,就是我們在程式中呼叫的讀取資料函式不能及時的把緩衝區中的資料拿出來,而下一個資料又到來並有一部分放入的緩衝區末尾,等我們讀取資料時就是一個粘包。(放資料的速度 > 應用層拿資料速度) 在這裡插入圖片描述
84. OSI 的七層模型都有哪些?

  • 應用層:網路服務與終端使用者的一個介面。
  • 表示層:資料的表示、安全、壓縮。
  • 會話層:建立、管理、終止會話。
  • 傳輸層:定義傳輸資料的協議埠號,以及流控和差錯校驗。
  • 網路層:進行邏輯地址定址,實現不同網路之間的路徑選擇。
  • 資料鏈路層:建立邏輯連線、進行硬體地址定址、差錯校驗等功能。
  • 物理層:建立、維護、斷開物理連線。

85. get 和 post 請求有哪些區別?

  • LET在瀏覽器回退時是無害的,而POST會再次提交請求。
  • GET產生的URL地址可以被Bookmark,而POST不可以。
  • GET請求會被瀏覽器主動cache,而POST不會,除非手動設定。
  • GET請求只能進行url編碼,而POST支援多種編碼方式。
  • GET請求引數會被完整保留在瀏覽器歷史記錄裡,而POST中的引數不會被保留。
  • GET請求在URL中傳送的引數是有長度限制的,而POST麼有。
  • 引數的資料型別,GET只接受ASCII字元,而POST沒有限制。
  • ET比POST更不安全,因為引數直接暴露在URL上,所以不能用來傳遞敏感資訊。
  • GET引數通過URL傳遞,POST放在Request body中。

86. 如何實現跨域?

方式一:圖片ping或script標籤跨域

圖片ping常用於跟蹤使用者點選頁面或動態廣告曝光次數。
script標籤可以得到從其他來源資料,這也是JSONP依賴的根據。

方式二:JSONP跨域

JSONP(JSON with Padding)是資料格式JSON的一種“使用模式”,可以讓網頁從別的網域要資料。根據 XmlHttpRequest 物件受到同源策略的影響,而利用

  • 只能使用Get請求
  • 不能註冊success、error等事件監聽函式,不能很容易的確定JSONP請求是否失敗
  • JSONP是從其他域中載入程式碼執行,容易受到跨站請求偽造的攻擊,其安全性無法確保

方式三:CORS

Cross-Origin Resource Sharing(CORS)跨域資源共享是一份瀏覽器技術的規範,提供了 Web 服務從不同域傳來沙盒指令碼的方法,以避開瀏覽器的同源策略,確保安全的跨域資料傳輸。現代瀏覽器使用CORS在API容器如XMLHttpRequest來減少HTTP請求的風險來源。與 JSONP 不同,CORS 除了 GET 要求方法以外也支援其他的 HTTP 要求。伺服器一般需要增加如下響應頭的一種或幾種:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

12345

跨域請求預設不會攜帶Cookie資訊,如果需要攜帶,請配置下述引數:

"Access-Control-Allow-Credentials": true
// Ajax設定
"withCredentials": true

1234

方式四:window.name+iframe

window.name通過在iframe(一般動態建立i)中載入跨域HTML檔案來起作用。然後,HTML檔案將傳遞給請求者的字串內容賦值給window.name。然後,請求者可以檢索window.name值作為響應。

  • iframe標籤的跨域能力;
  • indow.name屬性值在文件重新整理後依舊存在的能力(且最大允許2M左右)。

每個iframe都有包裹它的window,而這個window是top window的子視窗。contentWindow屬性返回元素的Window物件。你可以使用這個Window物件來訪問iframe的文件及其內部DOM。

<!-- 
 下述用埠 
 10000表示:domainA
 10001表示:domainB
-->

<!-- localhost:10000 -->
<script>
  var iframe = document.createElement('iframe');
  iframe.style.display = 'none'; // 隱藏

  var state = 0; // 防止頁面無限重新整理
  iframe.onload = function() {
      if(state === 1) {
          console.log(JSON.parse(iframe.contentWindow.name));
          // 清除建立的iframe
          iframe.contentWindow.document.write('');
          iframe.contentWindow.close();
          document.body.removeChild(iframe);
      } else if(state === 0) {
          state = 1;
          // 載入完成,指向當前域,防止錯誤(proxy.html為空白頁面)
          // Blocked a frame with origin "http://localhost:10000" from accessing a cross-origin frame.
          iframe.contentWindow.location = 'http://localhost:10000/proxy.html';
      }
  };

  iframe.src = 'http://localhost:10001';
  document.body.appendChild(iframe);
</script>

<!-- localhost:10001 -->
<!DOCTYPE html>
...
<script>
  window.name = JSON.stringify({a: 1, b: 2});
</script>
</html>

123456789101112131415161718192021222324252627282930313233343536373839

方式五:window.postMessage()

HTML5新特性,可以用來向其他所有的 window 物件傳送訊息。需要注意的是我們必須要保證所有的指令碼執行完才傳送 MessageEvent,如果在函式執行的過程中呼叫了它,就會讓後面的函式超時無法執行。

下述程式碼實現了跨域儲存localStorage

<!-- 
 下述用埠 
 10000表示:domainA
 10001表示:domainB
-->

<!-- localhost:10000 -->
<iframe src="http://localhost:10001/msg.html" name="myPostMessage" style="display:none;">
</iframe>

<script>
  function main() {
      LSsetItem('test', 'Test: ' + new Date());
      LSgetItem('test', function(value) {
          console.log('value: ' + value);
      });
      LSremoveItem('test');
  }

  var callbacks = {};
  window.addEventListener('message', function(event) {
      if (event.source === frames['myPostMessage']) {
          console.log(event)
          var data = /^#localStorage#(\d+)(null)?#([\S\s]*)/.exec(event.data);
          if (data) {
              if (callbacks[data[1]]) {
                  callbacks[data[1]](data[2] === 'null' ? null : data[3]);
              }
              delete callbacks[data[1]];
          }
      }
  }, false);

  var domain = '*';
  // 增加
  function LSsetItem(key, value) {
      var obj = {
          setItem: key,
          value: value
      };
      frames['myPostMessage'].postMessage(JSON.stringify(obj), domain);
  }
  // 獲取
  function LSgetItem(key, callback) {
      var identifier = new Date().getTime();
      var obj = {
          identifier: identifier,
          getItem: key
      };
      callbacks[identifier] = callback;
      frames['myPostMessage'].postMessage(JSON.stringify(obj), domain);
  }
  // 刪除
  function LSremoveItem(key) {
      var obj = {
          removeItem: key
      };
      frames['myPostMessage'].postMessage(JSON.stringify(obj), domain);
  }
</script>

<!-- localhost:10001 -->
<script>
  window.addEventListener('message', function(event) {
    console.log('Receiver debugging', event);
    if (event.origin == 'http://localhost:10000') {
      var data = JSON.parse(event.data);
      if ('setItem' in data) {
        localStorage.setItem(data.setItem, data.value);
      } else if ('getItem' in data) {
        var gotItem = localStorage.getItem(data.getItem);
        event.source.postMessage(
          '#localStorage#' + data.identifier +
          (gotItem === null ? 'null#' : '#' + gotItem),
          event.origin
        );
      } else if ('removeItem' in data) {
        localStorage.removeItem(data.removeItem);
      }
    }
  }, false);
</script>

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283

注意Safari一下,會報錯:

Blocked a frame with origin “http://localhost:10001” from 
accessing a frame with origin “http://localhost:10000. 
Protocols, domains, and ports must match.

1234

避免該錯誤,可以在Safari瀏覽器中勾選開發選單==>停用跨域限制。或者只能使用伺服器端轉存的方式實現,因為Safari瀏覽器預設只支援CORS跨域請求。

方式六:修改document.domain跨子域

前提條件:這兩個域名必須屬於同一個基礎域名!而且所用的協議,埠都要一致,否則無法利用document.domain進行跨域,所以只能跨子域

在根域範圍內,允許把domain屬性的值設定為它的上一級域。例如,在”aaa.xxx.com”域內,可以把domain設定為 “xxx.com” 但不能設定為 “xxx.org” 或者”com”。

現在存在兩個域名aaa.xxx.com和bbb.xxx.com。在aaa下嵌入bbb的頁面,
由於其document.name不一致,無法在aaa下操作bbb的js。
可以在aaa和bbb下通過js將document.name = 'xxx.com';
設定一致,來達到互相訪問的作用。

12345

方式七:WebSocket

WebSocket protocol 是HTML5一種新的協議。它實現了瀏覽器與伺服器全雙工通訊,同時允許跨域通訊,是server push技術的一種很棒的實現。相關文章,請檢視:WebSocket、WebSocket-SockJS

需要注意:WebSocket物件不支援DOM 2級事件偵聽器,必須使用DOM 0級語法分別定義各個事件。

方式八:代理

同源策略是針對瀏覽器端進行的限制,可以通過伺服器端來解決該問題

DomainA客戶端(瀏覽器) ==> DomainA伺服器 ==> DomainB伺服器 ==> DomainA客戶端(瀏覽器)

在這裡插入圖片描述

87.說一下 JSONP 實現原理?

jsonp 即 json+padding,動態建立script標籤,利用script標籤的src屬性可以獲取任何域下的js指令碼,通過這個特性(也可以說漏洞),伺服器端不在返貨json格式,而是返回一段呼叫某個函式的js程式碼,在src中進行了呼叫,這樣實現了跨域。

相關文章