分享一下我的面試知識點總結:
耦合性:也稱塊間聯系。指軟件系統結構中各模塊間相互聯系緊密程度的一種度量。模塊之間聯系越緊密,其耦合性就越強,模塊的獨立性則越差。模塊間耦合高低取決於模塊間接口的復雜性、調用的方式及傳遞的信息
內聚性:又稱塊內聯系。指模塊的功能強度的度量,即一個模塊內部各個元素彼此結合的緊密程度的度量。若一個模塊內各元素(語名之間、程序段之間)聯系的越緊密,則它的內聚性就越高。
TCP/IP五層模型:
應用層:是體系結構中的最高。直接為用戶的應用進程提供服務。在因特網中的應用層協議很多,如支持萬維網應用的HTTP協議,支持電子郵件的SMTP協議,支持文件傳送的FTP協議等等。
運輸層:運輸層主要使用以下兩種協議:
(1) 傳輸控制協議TCP(Transmission Control Protocol):面向連接的,數據傳輸的單位是報文段,能夠提供可靠的交付。
(2) 用戶數據包協議UDP(User Datagram Protocol):無連接的,數據傳輸的單位是用戶數據報,不保證提供可靠的交付,只能提供“盡最大努力交付”。
網絡層:負責為分組交換網上的不同主機提供通信服務。在發送數據時,網絡層把運輸層殘生的報文段或用戶數據報封裝成分組或包進行傳送。在TCP/IP體系中,由於網絡層使用IP協議,因此分組也叫做IP數據報,或簡稱為數據報。
數據鏈路層:網橋(現已很少使用)、以太網交換機(二層交換機)、網卡(其實網卡 是一半工作在物理層、一半工作在數據鏈路層)
物理層:在物理層上所傳數據的單位是比特。物理層的任務就是透明地傳送比特流。
三次握手:(三次握手和四次揮手詳見:http://www.cnblogs.com/ainyi/p/8629149.html)
所謂的“三次握手”即對每次發送的數據量是怎樣跟蹤進行協商使數據段的發送和接收同步,根據所接收到的數據量而確定的數據確認數及數據發送、接收完畢后何時撤消聯系,並建立虛連接。
第一次
第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SENT狀態,等待服務器確認;SYN:同步序列編號(Synchronize Sequence Numbers)。
第二次
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
第三次
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP連接成功)狀態,完成三次握手。
http協議:重中之重 在應用層
協議是指計算機通信網絡中兩台計算機之間進行通信所必須共同遵守的規定或規則,超文本傳輸協議(HTTP)是一種通信協議,它允許將超文本標記語言(HTML)文檔從Web服務器傳送到客戶端的瀏覽器。
HTTP協議,即超文本傳輸協議(Hypertext transfer protocol)。是一種詳細規定了瀏覽器和萬維網(WWW = World Wide Web)服務器之間互相通信的規則,通過因特網傳送萬維網文檔的數據傳送協議。
HTTP協議是用於從WWW服務器傳輸超文本到本地瀏覽器的傳送協議。它可以使瀏覽器更加高效,使網絡傳輸減少。它不僅保證計算機正確快速地傳輸超文本文檔,還確定傳輸文檔中的哪一部分,以及哪部分內容首先顯示(如文本先於圖形)等。
HTTP是一個應用層協議,由請求和響應構成,是一個標准的客戶端服務器模型。HTTP是一個無狀態的協議。
在Internet中所有的傳輸都是通過TCP/IP進行的。HTTP協議作為TCP/IP模型中應用層的協議也不例外。HTTP協議通常承載於TCP協議之上,有時也承載於TLS或SSL協議層之上,這個時候,就成了我們常說的HTTPS。如下圖所示:(SSL(Secure Sockets Layer 安全套接層),及其繼任者傳輸層安全(Transport Layer Security,TLS)是為網絡通信提供安全及數據完整性的一種安全協議。TLS與SSL在傳輸層對網絡連接進行加密。)
HTTP默認的端口號為80,HTTPS的端口號為443。
瀏覽網頁是HTTP的主要應用,但是這並不代表HTTP就只能應用於網頁的瀏覽。HTTP是一種協議,只要通信的雙方都遵守這個協議,HTTP就能有用武之地。比如咱們常用的QQ,迅雷這些軟件,都會使用HTTP協議(還包括其他的協議)。
二、簡史
它的發展是萬維網協會(World Wide Web Consortium)和Internet工作小組IETF(Internet Engineering Task Force)合作的結果,(他們)最終發布了一系列的RFC,RFC 1945定義了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定義了今天普遍使用的一個版本——HTTP 1.1。
三、特點
HTTP協議永遠都是客戶端發起請求,服務器回送響應。這樣就限制了使用HTTP協議,無法實現在客戶端沒有發起請求的時候,服務器將消息推送給客戶端。
HTTP協議的主要特點可概括如下:
1、支持客戶/服務器模式。支持基本認證和安全認證。
2、簡單快速:客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶與服務器聯系的類型不同。由於HTTP協議簡單,使得HTTP服務器的程序規模小,因而通信速度很快。
3、靈活:HTTP允許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type加以標記。
4、HTTP 0.9和1.0使用非持續連接:限制每次連接只處理一個請求,服務器處理完客戶的請求,並收到客戶的應答后,即斷開連接。HTTP 1.1使用持續連接:不必為每個web對象創建一個新的連接,一個連接可以傳送多個對象,采用這種方式可以節省傳輸時間。
5、無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味着如果后續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送的數據量增大。
無狀態協議:
協議的狀態是指下一次傳輸可以“記住”這次傳輸信息的能力。
http是不會為了下一次連接而維護這次連接所傳輸的信息,為了保證服務器內存。
比如客戶獲得一張網頁之后關閉瀏覽器,然后再一次啟動瀏覽器,再登陸該網站,但是服務器並不知道客戶關閉了一次瀏覽器。
由於Web服務器要面對很多瀏覽器的並發訪問,為了提高Web服務器對並發訪問的處理能力,在設計HTTP協議時規定Web服務器發送HTTP應答報文和文檔時,不保存發出請求的Web瀏覽器進程的任何狀態信息。這有可能出現一個瀏覽器在短短幾秒之內兩次訪問同一對象時,服務器進程不會因為已經給它發過應答報文而不接受第二期服務請求。由於Web服務器不保存發送請求的Web瀏覽器進程的任何信息,因此HTTP協議屬於無狀態協議(Stateless Protocol)。
HTTP協議是無狀態的和Connection: keep-alive的區別:
無狀態是指協議對於事務處理沒有記憶能力,服務器不知道客戶端是什么狀態。從另一方面講,打開一個服務器上的網頁和你之前打開這個服務器上的網頁之間沒有任何聯系。
HTTP是一個無狀態的面向連接的協議,無狀態不代表HTTP不能保持TCP連接,更不能代表HTTP使用的是UDP協議(無連接)。
從HTTP/1.1起,默認都開啟了Keep-Alive,保持連接特性,簡單地說,當一個網頁打開完成后,客戶端和服務器之間用於傳輸HTTP數據的TCP連接不會關閉,如果客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經建立的連接。
Keep-Alive不會永久保持連接,它有一個保持時間,可以在不同的服務器軟件(如Apache)中設定這個時間。
四、工作流程
一次HTTP操作稱為一個事務,其工作過程可分為四步:
1)首先客戶機與服務器需要建立連接。只要單擊某個超級鏈接,HTTP的工作開始。
2)建立連接后,客戶機發送一個請求給服務器,請求方式的格式為:統一資源標識符(URL)、協議版本號,后邊是MIME信息包括請求修飾符、客戶機信息和可能的內容。
3)服務器接到請求后,給予相應的響應信息,其格式為一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,后邊是MIME信息包括服務器信息、實體信息和可能的內容。
4)客戶端接收服務器所返回的信息通過瀏覽器顯示在用戶的顯示屏上,然后客戶機與服務器斷開連接。
如果在以上過程中的某一步出現錯誤,那么產生錯誤的信息將返回到客戶端,有顯示屏輸出。對於用戶來說,這些過程是由HTTP自己完成的,用戶只要用鼠標點擊,等待信息顯示就可以了。
HTTP是基於傳輸層的TCP協議,而TCP是一個端到端的面向連接的協議。所謂的端到端可以理解為進程到進程之間的通信。所以HTTP在開始傳輸之前,首先需要建立TCP連接,而TCP連接的過程需要所謂的“三次握手”。下圖所示TCP連接的三次握手。
在TCP三次握手之后,建立了TCP連接,此時HTTP就可以進行傳輸了。一個重要的概念是面向連接,既HTTP在傳輸完成之間並不斷開TCP連接。在HTTP1.1中(通過Connection頭設置)這是默認行為。
HTTP狀態碼:
100-199:表示信息性代碼,標示客戶端應該采取的其他動作,請求正在進行。
200-299:表示客戶請求成功。
300-399:表示用於已經移走的資源文件,指示新的地址。 重定向
400-499:表示由客戶端引發的錯誤。
500-599:表示由服務器端引發的錯誤。
404 沒找到頁面(not found)
403 禁止訪問(forbidden)
200 一切正常(ok)
302/307 臨時重定向
301 永久重定向
304 沒有被修改(not modified)(服務器返回304狀態,表示源文件沒有被修改)從緩存中讀取
設置狀態碼sendError(code,”Resource Not Found”);
按照響應信息的格式,先有狀態行,再有消息體,所以注意在使用PrintWriter向客戶端輸出信息之前,設置狀態碼
設置HTTP響應頭
目的用於告訴客戶端
發送回來的內容的類型
有多少內容被正被發送
發送內容的服務器的類型
設置響應頭的方法:setHeader()或setHeaders()。注意:設置響應頭只能是HTTP協議。所以setHeader和setHeaders()都是HttpServletResponse中的方法
設置HTTP消息體
response.getWriter()獲得打印字符流,可以輸出文本
response.getOutputStream()獲得輸出字節流,可以發送二進制數據。
重定向原理
重定向調用方法:
response.sendRedirect(“http://127.0.0.1:8080/lovobook/bar.html“);
1,
瀏覽器向服務器發送HTTP請求。
2,服務器接收到請求后,如果調用response.sendRedirect()方法,表示資源已被移走。則發送一個302的狀態碼和location的響應頭。在location響應頭指明要轉發的地址。 302:臨時重定向
3,瀏覽器在接收到302狀態碼后,會讀取location響應頭的內容,並將地址欄的值賦為location響應頭的內容。從而再向服務器發出第二次請求。由於是二次請求,所以重定向不能獲得封裝在request中的屬性信息
內部轉發和重定向的區別:
轉發是服務器行為,重定向是客戶端行為
轉發的速度快;重定向速度慢
1、 內部轉發由requestDispatcher發出,重定向由response發出。
2、內部轉發是一次請求,重定向是兩次不同請求。
3、內部轉發可以取出request中封裝的數據(攜帶參數),重定向不能。
4、 轉發地址欄沒有變化,重定向地址欄有變化
5、內部轉發只能在服務器內部進行,重定向可以請求別的服務器。
5、 轉發不會執行轉發后的代碼,重定向會執行重定向之后的代碼
在servlet中調用轉發、重定向的語句如下:
//轉發到
request.getRequestDispatcher("new.jsp").forward(request, response);
//重定向
response.sendRedirect("new.jsp");
在controller層轉發、重定向語句如下:
//轉發
@RequestMapping("/index")
public String index(){
//some code
return "index/index"; //默認是轉發,不會顯示轉發路徑
}
@RequestMapping("/index")
public ModelAndView index(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index/index"); //默認轉發,跳到此頁面
return modelAndView;
}
上述轉發的路徑是轉發到存放jsp頁面的路徑,就是index文件夾下的index.jsp。
但如果加上forward,
就是轉發到controller層的控制類下的方法(命名空間/RequestMapping)
return "forward:index/index";
modelAndView.setViewName("forward:index/index");
//重定向 (加上redirect)
@RequestMapping("/index")
public String index(){
//some code
return "redirect:index/index"; //地址欄顯示重定向路徑
}
@RequestMapping("/index")
public ModelAndView index(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:index/index");
return modelAndView;
}
若要返回命名空間的上一級,用../
轉發過程:客戶瀏覽器發送http請求,web服務器接受此請求,調用內部的一個方法在容器內部完成請求處理和轉發動作,將目標資源發送給客戶;在這里,轉發的路徑必須是同一個web容器下的url,其不能轉向到其他的web路徑上去,中間傳遞的是自己的容器內的request。在客戶瀏覽器路徑欄顯示的仍然是其第一次訪問的路徑,也就是說客戶是感覺不到服務器做了轉發的。轉發行為是瀏覽器只做了一次訪問請求。
重定向過程:客戶瀏覽器發送http請求,web服務器接受后發送302狀態碼響應及對應新的location給客戶瀏覽器,客戶瀏覽器發現是302響應,則自動再發送一個新的http請求,請求url是新的location地址,服務器根據此請求尋找資源並發送給客戶。在這里location可以重定向到任意URL,既然是瀏覽器重新發出了請求,則就沒有什么request傳遞的概念了。在客戶瀏覽器路徑欄顯示的是其重定向的路徑,客戶可以觀察到地址的變化的。重定向行為是瀏覽器做了至少兩次的訪問請求的。
重定向,其實是兩次request
第一次,客戶端request A,服務器響應,並response回來,告訴瀏覽器,你應該去B。這個時候IE可以看到地址變了,而且歷史的回退按鈕也亮了。重定向可以訪問自己web應用以外的資源。在重定向的過程中,傳輸的信息會被丟失。
JSP九大內置對象
在翻譯好的類中,在_jspService()中有九個局部變量,並都做了初始化。由於我們在JSP中書寫的內容都是豐富_jspService()方法,所以可以直接使用這些局部變量,這就是隱式對象
四個作用域:
page:在一個頁面內保存屬性,跳轉之后無效。page對象代表JSP本身,只有在JSP頁面內才是合法的。
request:作用於請求 :在一次服務請求范圍內,服務器跳轉后依然有效,request對象代表了客戶端的請求信息,主要用於接受通過HTTP協議傳送到服務器的數據
session:作用於會話 :在一次會話范圍內,無論何種跳轉都可以使用,但是關閉瀏覽器后,新開瀏覽器無法使用。session對象是由服務器自動創建的與用戶請求相關的對象。服務器為每個用戶都生成一個session對象,用於保存該用戶的信息,跟蹤用戶的操作狀態
application:作用於全局(類型是ServletContext) :整個服務器上保存,所有用戶都可以使用。application對象可將信息保存在服務器中,直到服務器關閉,否則application對象中保存的信息會在整個應用中都有效
response:代表的是對客戶端的響應,主要是將JSP容器處理過的對象傳回到客戶端
out:對象用於在Web瀏覽器內輸出信息,並且管理應用服務器上的輸出緩沖區pageContext 對象的作用是取得任何范圍的參數
config:對象的主要作用是取得服務器的配置信息
exception:對象的作用是顯示異常信息
關系型數據庫遵循ACID規則
事務在英文中是transaction,和現實世界中的交易很類似,它有如下四個特性:
事務的特性:
1、A (Atomicity) 原子性
原子性很容易理解,也就是說事務里的所有操作要么全部做完,要么都不做,事務成功的條件是事務里的所有操作都成功,只要有一個操作失敗,整個事務就失敗,需要回滾。
比如銀行轉賬,從A賬戶轉100元至B賬戶,分為兩個步驟:1)從A賬戶取100元;2)存入100元至B賬戶。這兩步要么一起完成,要么一起不完成,如果只完成第一步,第二步失敗,錢會莫名其妙少了100元。
2、C (Consistency) 一致性
一致性也比較容易理解,也就是說數據庫要一直處於一致的狀態,事務的運行不會改變數據庫原本的一致性約束。
例如現有完整性約束a+b=10,如果一個事務改變了a,那么必須得改變b,使得事務結束后依然滿足a+b=10,否則事務失敗。
3、I (Isolation) 獨立性
所謂的獨立性是指並發的事務之間不會互相影響,如果一個事務要訪問的數據正在被另外一個事務修改,只要另外一個事務未提交,它所訪問的數據就不受未提交事務的影響。
比如現在有個交易是從A賬戶轉100元至B賬戶,在這個交易還未完成的情況下,如果此時B查詢自己的賬戶,是看不到新增加的100元的。
4、D (Durability) 持久性
持久性是指一旦事務提交后,它所做的修改將會永久的保存在數據庫上,即使出現宕機也不會丟失。
session 和 cookie
1.由於HTTP協議是無狀態的協議,所以服務端需要記錄用戶的狀態時,就需要用某種機制來識具體的用戶,這個機制就是Session.典型的場景比如購物車,當你點擊下單按鈕時,由於HTTP協議無狀態,所以並不知道是哪個用戶操作的,所以服務端要為特定的用戶創建了特定的Session,用用於標識這個用戶,並且跟蹤用戶,這樣才知道購物車里面有幾本書。這個Session是保存在服務端的,有一個唯一標識。在服務端保存Session的方法很多,內存、數據庫、文件都有。集群的時候也要考慮Session的轉移,在大型的網站,一般會有專門的Session服務器集群,用來保存用戶會話,這個時候 Session 信息都是放在內存的,使用一些緩存服務比如Memcached之類的來放 Session。
2. 思考一下服務端如何識別特定的客戶?這個時候Cookie就登場了。每次HTTP請求的時候,客戶端都會發送相應的Cookie信息到服務端。實際上大多數的應用都是用 Cookie 來實現Session跟蹤的,第一次創建Session的時候,服務端會在HTTP協議中告訴客戶端,需要在 Cookie 里面記錄一個Session ID,以后每次請求把這個會話ID發送到服務器,我就知道你是誰了。有人問,如果客戶端的瀏覽器禁用了 Cookie 怎么辦?一般這種情況下,會使用一種叫做URL重寫的技術來進行會話跟蹤,即每次HTTP交互,URL后面都會被附加上一個諸如 sid=xxxxx 這樣的參數,服務端據此來識別用戶。
3. Cookie其實還可以用在一些方便用戶的場景下,設想你某次登陸過一個網站,下次登錄的時候不想再次輸入賬號了,怎么辦?這個信息可以寫到Cookie里面,訪問網站的時候,網站頁面的腳本可以讀取這個信息,就自動幫你把用戶名給填了,能夠方便一下用戶。這也是Cookie名稱的由來,給用戶的一點甜頭。
所以,總結一下:
Session是在服務端保存的一個數據結構,用來跟蹤用戶的狀態,這個數據可以保存在集群、數據庫、文件中;
Cookie是客戶端保存用戶信息的一種機制,用來記錄用戶的一些信息,也是實現Session的一種方式。存儲量太小,只有 4KB
下面介紹HTTP協議定義的緩存機制。
Expires策略
Expires是Web服務器響應消息頭字段,在響應http請求時告訴瀏覽器在過期時間前瀏覽器可以直接從瀏覽器緩存取數據,而無需再次請求。
注:Date頭域表示消息發送的時間,時間的描述格式由rfc822定義。例如,Date: Mon,31 Dec 2001 04:25:57GMT。
Web服務器告訴瀏覽器在2012-11-28 03:30:01這個時間點之前,可以使用緩存文件。發送請求的時間是2012-11-28 03:25:01,即緩存5分鍾。
不過Expires 是HTTP 1.0的東西,現在默認瀏覽器均默認使用HTTP 1.1,所以它的作用基本忽略。
Cache-control策略(重點關注)
Cache-Control與Expires的作用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據還是重新發請求到服務器取數據。只不過Cache-Control的選擇更多,設置更細致,如果同時設置的話,其優先級高於Expires。
http協議頭Cache-Control : |
值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age 各個消息中的指令含義如下:
|
還是上面那個請求,web服務器返回的Cache-Control頭的值為max-age=300,即5分鍾(和上面的Expires時間一致,這個不是必須的)。
Last-Modified/If-Modified-Since
Last-Modified/If-Modified-Since要配合Cache-Control使用。
l Last-Modified:標示這個響應資源的最后修改時間。由服務器往客戶端發送的http頭,web服務器在響應請求時,告訴瀏覽器資源的最后修改時間。
l If-Modified-Since:響應資源最后修改的時間,由客戶端往服務端發送的頭。再次請求本地存在的 cache 頁面時,客戶端會通過 If-Modified-Since 頭將先前服務器端發過來的 Last-Modified 最后修改時間戳發送回去,這是為了讓服務器端進行驗證,通過這個時間戳判斷客戶端的頁面是否是最新的,如果不是最新的,則返回200,返回新的內容。如果是最新的,則 返回 304 告訴客戶端其本地 cache 的頁面是最新的,於是客戶端就可以直接從本地加載頁面了,這樣在網絡上傳輸的數據就會大大減少,同時也減輕了服務器的負擔。
Etag/If-None-Match
Etag/If-None-Match也要配合Cache-Control使用。
l Etag:服務端往客服端發送的頭。web服務器響應請求時,告訴瀏覽器當前資源在服務器的唯一標識(生成規則由服務器決定)。Apache中,ETag的值,默認是對文件的索引節(INode),大小(Size)和最后修改時間(MTime)進行Hash后得到的。
l If-None-Match:(Etags的值),客戶端往服務端發送的頭。工作原理是在HTTP Response中添加ETags信息。當客戶端再次請求該資源時,將在HTTP Request中加入If-None-Match信息(ETags的值)。如果服務器驗證資源的ETags沒有改變(該資源沒有改變),將返回一個304狀態;否則,服務器將返回200狀態,並返回該資源和新的ETags。
既有Last-Modified為何還要Etag?
你可能會覺得使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,為什么還需要Etag(實體標識)呢?HTTP1.1中Etag的出現主要是為了解決幾個Last-Modified比較難解決的問題:
l Last-Modified標注的最后修改只能精確到秒級,如果某些文件在1秒鍾以內,被修改多次的話,它將不能准確標注文件的修改時間
l 如果某些文件會被定期生成,當有時內容並沒有任何變化,但Last-Modified卻改變了,導致文件沒法使用緩存
l 有可能存在服務器沒有准確獲取文件修改時間,或者與代理服務器時間不一致等情形
Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一標識符,能夠更加准確的控制緩存。Last-Modified與ETag是可以一起使用的,服務器會優先驗證ETag,一致的情況下,才會繼續比對Last-Modified,最后才決定是否返回304。
用戶行為與緩存
瀏覽器緩存行為還有用戶的行為有關!!!
用戶操作 |
Expires/Cache-Control |
Last-Modified/Etag |
地址欄回車 |
有效 |
有效 |
頁面鏈接跳轉 |
有效 |
有效 |
新開窗口 |
有效 |
有效 |
前進、后退 |
有效 |
有效 |
F5刷新 |
無效 |
有效 |
Ctrl+F5刷新 |
無效 |
無效 |
總結
瀏覽器第一次請求:
瀏覽器再次請求時:
從輸入URL到頁面加載完成的過程中都發生了什么事情?
- 輸入地址URL
- 利用DNS查找域名的 IP 地址
這一步包括 DNS 具體的查找過程,包括:瀏覽器緩存->系統緩存->路由器緩存... - 根據IP建立TCP連接(三次握手)
- 瀏覽器向 web 服務器發送一個 HTTP 請求
- 服務器的永久重定向響應(從 http://example.com 到 http://www.example.com)
- 瀏覽器跟蹤重定向地址
- 服務器處理請求
- 服務器返回一個 HTTP 響應
- 瀏覽器渲染頁面,構建DOM樹,顯示 HTML
- 瀏覽器發送請求獲取嵌入在 HTML 中的資源(如圖片、音頻、視頻、CSS、JS等等)
- 瀏覽器發送異步請求
HTTP 協議中 URI 和 URL 有什么區別?
統一資源標志符URI:就是在某一規則下能把一個資源獨一無二地標識出來。
拿人做例子,身份證號就是URI,通過身份證號能讓我們能且僅能確定一個人。
統一資源定位符URL:也拿人做例子:動物住址協議://地球/中國/浙江省/杭州市/西湖區/某大學/14號宿舍樓/525號寢/張三.人
可以看到,這個字符串同樣標識出了唯一的一個人,起到了URI的作用,所以URL是URI的子集。URL是以描述資源的位置來唯一確定一個資源的。
所以不論是用定位的方式還是用編號的方式,我們都可以唯一確定一個人,都是URl的一種實現,而URL就是用定位的方式實現的URI。
回到Web上,假設所有的Html文檔都有唯一的編號,記作html:xxxxx,xxxxx是一串數字,即Html文檔的身份證號碼,這個能唯一標識一個Html文檔,那么這個號碼就是一個URI。
而URL則通過描述是哪個主機上哪個路徑上的文件來唯一確定一個資源,也就是定位的方式來實現的URI。
JavaScript事件流:
事件傳播的順序對應瀏覽器的兩種事件流模型:捕獲型事件流和冒泡型事件流。
DOM標准采用捕獲+冒泡。兩種事件流都會觸發DOM的所有對象,從document對象開始,也在document對象結束。
DOM標准規定事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。
事件捕獲階段:實際目標(<div>)在捕獲階段不會接收事件。也就是在捕獲階段,事件從document到<html>再到<body>就停止了。上圖中為1~3.
處於目標階段:事件在<div>上發生並處理。但是事件處理會被看成是冒泡階段的一部分。上圖中為4
冒泡階段:事件又傳播回文檔。上圖中為5~7
阻止事件冒泡:
若有一a標簽:
<a href="http://www.baidu.com" target="_blank"></a>
1.event.stopPropagation()方法
這是阻止事件的冒泡方法,不讓事件向documen上蔓延,但是默認事件任然會執行,當你掉用這個方法的時候,如果點擊一個連接,這個連接仍然會被打開,不會冒泡到父元素直至document
2.event.preventDefault()方法
這是阻止默認事件的方法,調用此方法是,連接不會被打開,但是會發生冒泡,冒泡會傳遞到上一層的父元素;
3.return false ;
這個方法比較暴力,他會同時阻止事件冒泡也會阻止默認事件;寫上此代碼,連接不會被打開,事件也不會傳遞到上一層的父元素;可以理解為return false就等於同時調用了event.stopPropagation()和event.preventDefault(),但可以在return false之前執行一些必要代碼。但標簽內部的事件不會執行
跨域問題
了解同源政策:所謂"同源"指的是"三個相同"。
- 協議相同
- 域名相同
- 端口相同
同源政策的目的:是為了保證用戶信息的安全,防止惡意的網站竊取數據。
設想這樣一種情況:A網站是一家銀行,用戶登錄以后,又去瀏覽其他網站。如果其他網站可以讀取A網站的 Cookie,會發生什么?
很顯然,如果 Cookie 包含隱私(比如存款總額),這些信息就會泄漏。更可怕的是,Cookie 往往用來保存用戶的登錄狀態,如果用戶沒有退出登錄,其他網站就可以冒充用戶,為所欲為。因為瀏覽器同時還規定,提交表單不受同源政策的限制。
由此可見,"同源政策"是必需的,否則 Cookie 可以共享,互聯網就毫無安全可言了。
解決跨域問題:
首先假設你請求數據的網站為B。要看你是否可以控制(修改里面的代碼)。
1 jsonp 缺點:只能get請求 ,需要修改B網站的代碼
2 cors 這個方案缺點 是 ie6 7 兼容不好(倒是不見得要兼容)。需要B網站在響應中加頭
3 postMessage 缺點也是 ie6 7 兼容不好(倒是不見得要兼容)。需要修改B網站的代碼
4 iframe window.name 傳值得方式很巧妙,兼容性也很好。但是也是需要你能修改B網站代碼
5 服務端主動請求B網站,兼容性好而且你客戶端的代碼還是原來的ajax,缺點是感覺不好。(服務器端是不存在跨域安全限制的)
6 類似5 用nginx把B網站的數據url反向代理。
如果你不能修改B網站的代碼老老實實5 6 方案
如果能修改B網站 方案2的修改應該是最簡單的。
就算是B網站你可以修改,還有種需求處理起來比較麻煩的,就是有的數據需要登錄之后才能取。
最直接的方案,B網站提供數據的url 進去先提供用戶名密碼,走下登錄再走取數據,最后返回數據。
Jsonp解決跨域:
1 $.ajax({ 2 3 url:url, 4 5 dataType:'jsonp', 6 7 processData: false, 8 9 type:'get', 10 11 success:function(data){ 12 13 alert(data.name); 14 15 }, 16 17 error:function(XMLHttpRequest, textStatus, errorThrown) { 18 19 alert(XMLHttpRequest.status); 20 21 alert(XMLHttpRequest.readyState); 22 23 alert(textStatus); 24 25 } 26 27 });
jsonp其實返回的是一個JS函數調用代碼,把返回的數據和客戶端能調用的函數名拼接在一起,放到瀏覽器環境下,去執行而得到最終的服務端數據,也就是jsonp是一種json數據的傳輸方式而不是格式
jsonp格式:
callback({
"message":"獲取成功",
"state":"1",
"result":{"name":"工作組1","id":1,"description":"11"}
})
jsonp 的實現原理,詳情看:https://github.com/Krryxa/WORK-LEARNING/issues/23
介紹一下閉包和閉包常用場景
閉包是指有權訪問另一個函數作用域中的局部變量的函數. 創建閉包常見方式,就是在一個函數內部創建另一個函數.
應用場景 設置私有變量和方法
不適合場景:返回閉包的函數是個非常大的函數
閉包的缺點就是常駐內存,會增大內存使用量,使用不當很容易造成內存泄露。
為什么會出現閉包這種東西,解決了什么問題
受JavaScript鏈式作用域結構的影響,父級變量中無法訪問到子級的變量值,為了解決這個問題,才使用閉包這個概念
詳情看:https://github.com/Krryxa/WORK-LEARNING/issues/20
語義化:
像html5的新的標簽header,footer,section等就是語義化
一方面,語義化就是讓計算機能夠快速的讀懂內容,高效的處理信息,可以對搜索引擎更友好。
另一方面,便於與他人的協作,他人通過讀代碼就可以理解你網頁標簽的意義。
box-sizing屬性:
content-box 是W3C的標准盒模型 元素寬度=內容寬度+padding+border
border-box 是ie的怪異盒模型 他的元素寬度等於內容寬度, 內容寬度包括了 padding+border,只要設定了寬度高度,再設置padding 和 border 也不會撐大
比如有時候在元素基礎上添加內距padding或border會將布局撐破 但是使用border-box就可以輕松完成
Inherit:規定應從父元素繼承 box-sizing 屬性的值。
介紹一下HTML5的新特性
- 新的DOCTYPE聲明 <!DOCTYPE html>
- 完全支持css3
- video和audio
- 本地存儲
- 語義化標簽 <header><nav><aside><article><footer>
- Canvas圖形
- 新事件 如ondrag onresize
- HTML5 拖放
- 地理定位
Css3 新特性:
圓角邊框border-radius,添加陰影框 box-shadow / text-shadow
顏色漸變
2d 3d 轉換:transform
過度 transition
動畫 @keyframes
媒體查詢 @media 響應式優化
語義化標簽:
HTML5增加了新的內容標簽,這些標簽帶有一定的語義,使搜索引擎爬取你的網站信息更高效。
HTML4中的內容標簽級別相同,無法區分各部分內容。而HTML5中的內容標簽互相獨立,級別不同,搜索引擎以及統計軟件等均可快速識別各部分內容。
本地存儲(Local Storage)
最早的Cookies自然是大家都知道,問題主要就是太小,大概也就4KB的樣子,而且IE6只支持每個域名20個cookies,太少了。
在HTML5中,本地存儲是一個window的屬性,包括localStorage和sessionStorage,從名字應該可以很清楚的辨認二者的區別,前者是一直存在本地的,后者只是伴隨着session,窗口一旦關閉就沒了。二者用法完全相同
- localStorage - 沒有時間限制的數據存儲
- sessionStorage - 針對一個 session 的數據存儲
Label的作用是什么?是怎么用的?
label標簽來定義表單控制間的關系,當用戶選擇該標簽時,瀏覽器會自動將焦點轉到和標簽相關的表單控件上。
<label for="Name">Number:</label>
<input type=“text“name="Name" id="Name"/>
<label>Date:<input type="text" name="B"/></label>
拖拽
是一種常見的特性,即抓取對象以后拖到另一個位置。在 HTML5 中,拖放是標准的一部分,任何元素都能夠拖放。
設置元素為可拖放
首先,為了使元素可拖動,把 draggable 屬性設置為 true :
- <img draggable="true">
當離開的時候 ondragleave
當進入的時候ondragenter
拖動什么 - ondragstart 和 setData()
放到何處 - ondragover :內部移動
進行放置 - ondrop
原生ajax:
1 //創建一個FormData對象:用一些鍵值對來模擬一系列表單控件:即把form中所有表單元素的name與value組裝成一個queryString 2 3 var form = new FormData(); 4 5 //設置要傳遞的參數 6 7 form.append("doc", fileObj); 8 9 // 創建一個ajax對象 10 11 var xhr = new XMLHttpRequest(); 12 13 //規定請求的類型、URL 以及是否異步處理請求。true為異步 14 15 //請求是異步的。因為要實時獲取到上傳的進度,則請求需是異步的,如果是同步的話,會直到請求完成才能獲取到響應 16 17 xhr.open("post", url, true); 18 19 //發送http請求:將請求發送到服務器,與后台交互 20 21 xhr.send(form); //也可以不攜帶參數,直接 xhr.send(); 22 23 //響應成功進入的回調函數 24 25 xhr.onreadystatechange = function(){ 26 27 //狀態4和200代表和服務器端交互成功 28 29 if(xhr.readyState==4 && xhr.status==200){ 30 31 //獲取上傳成功的返回數據 32 33 var data = xhr.responseText.trim(); 34 35 jdata = eval("("+data+")"); 36 37 } 38 39 };
//xhr.open() 與 xhr.send() 一起用
//前者是規定請求的類型、url,后者是發送請求到這個url
瀏覽器兼容問題解決:
問題一:不同瀏覽器的標簽默認的外補丁和內補丁不同
- 問題症狀:隨便寫幾個標簽,不加樣式控制的情況下,各自的margin 和padding差異較大。
- 碰到頻率:100%
- 解決方案:css里 *{margin:0;padding:0;}
- 備注:這個是最常見的也是最易解決的一個瀏覽器兼容性問題,幾乎所有的css文件開頭都會用通配符*來設置各個標簽的內外補丁是0。通配符*代表所有的
css3特殊子元素選擇器:
:last-child 選擇元素最后一個孩子
:first-child 選擇元素第一個孩子
:nth-child(1) 按照第幾個孩子給它設置樣式
:nth-child(even) 按照偶數
:nth-child(odd) 按照奇數
css3偽類:
a:link {color: #FF0000} /* 未訪問的鏈接 */
a:visited {color: #00FF00} /* 已訪問的鏈接 */
a:hover {color: #FF00FF} /* 鼠標移動到鏈接上 */
a:active {color: #0000FF} /* 選定的鏈接 */
:after 選擇器在被選元素的內容后面插入內容。使用 content 屬性來指定要插入的內容。
js 刪除數組幾種方法
詳情看:https://github.com/Krryxa/WORK-LEARNING/issues/9
Array 對象方法
連接兩個或更多的數組,並返回結果。 |
|
把數組的所有元素放入一個字符串。元素通過指定的分隔符進行分隔。 |
|
刪除並返回數組的最后一個元素(改變原數組) |
|
向數組的末尾添加一個或更多元素,並返回新的長度。(改變原數組) |
|
顛倒數組中元素的順序。(改變原數組) |
|
刪除並返回數組的第一個元素(改變原數組) |
|
從某個已有的數組返回選定的元素 |
|
對數組的元素進行排序(改變原數組) |
|
刪除元素,並向數組添加新元素。(改變原數組) |
|
返回該對象的源代碼。 |
|
把數組轉換為字符串,並返回結果。 |
|
把數組轉換為本地數組,並返回結果。 |
|
向數組的開頭添加一個或更多元素,並返回新的長度。(改變原數組) |
|
返回數組對象的原始值 |
詳情看:https://github.com/Krryxa/WORK-LEARNING/issues/9
箭頭函數不綁定this,arguments,自家沒有this,找的是上一級的this
如何更改this指向:
1) new、call、apply、bind
2) let _this = this;
3) => 箭頭函數
如何確定this是誰,看誰調動的, .前面是誰this就是誰
第一種: new關鍵字改變this指向
1 // 構造函數版 this 2 function Fn(){ 3 this.user = "筱月"; // 此時的 this 指向 window 4 } 5 let a = new Fn(); 6 console.log(a.user); //筱月
用變量a創建了一個 Fn 的實例,此時僅僅只是創建,並沒有執行,而調用這個函數 Fn 的是對象 a,那么 this 指向的自然是對象 a,那么為什么對象 a 中會有 user,因為你已經復制了一份 Fn 函數到對象 a 中,用了 new 關鍵字就等同於復制了一份
第二種: call()
注意如果 call 和 apply 的第一個參數寫的是null,那么 this 指向的是 window 對象
1 let a = { 2 user:"筱月", 3 fn:function(){ 4 console.log(this.user); //筱月 5 } 6 } 7 let b = a.fn; 8 // 執行 b 方法,call 的第一個參數是改變 this 指向,b 方法的 this 就是指向 call 第一個參數的對象 9 b.call(a); // 若不用call,則 b() 執行后 this 指的是 Window 對象
// call方法除了第一個參數以外還可以添加多個參數,如下: let a = { user:"筱月", fn:function(e,ee){ console.log(this.user); // 筱月 console.log(e+ee); // 3 } } let b = a.fn; b.call(a,1,2); // 輸出 筱月 3
第三種:apply()
1 let a = { 2 user:"筱月", 3 fn:function(){ 4 console.log(this.user); //筱月 5 } 6 } 7 8 let b = a.fn; 9 b.apply(a); 10 11 // apply方法和call方法有些相似,它也可以改變this的指向,也可以有多個參數,但是不同的是,第二個參數必須是一個數組,如下: 12 13 let a = { 14 user:"筱月", 15 fn:function(e,ee){ 16 console.log(this.user); //筱月 17 console.log(e+ee); //11 18 } 19 } 20 21 let b = a.fn; 22 b.apply(a,[10,1]); 23 24 // 注意如果 call 和 apply 的第一個參數寫的是null,那么this指向的是window對象 25 26 let a = { 27 user:"筱月", 28 fn:function(){ 29 console.log(this); // Window {...} 30 } 31 } 32 33 let b = a.fn; 34 b.apply(null);
第四種:bind()
bind方法和call、apply方法有些不同,如下:
bind 方法返回的是一個修改過后的函數,此時並沒有調用,需要將 bind 方法返回的函數執行 才能調用
1 let a = { 2 user:"筱月", 3 fn:function(){ 4 console.log(this.user); //筱月 5 } 6 7 } 8 let b = a.fn; 9 let c = b.bind(a); // 方法還沒執行,bind 方法返回的是一個修改過后的函數 10 c(); // 輸出:筱月 11 12 // 同樣bind也可以有多個參數,並且參數可以在 bind 返回的函數執行的時候再次添加,但是要注意的是,參數是按照形參的順序進行的 13 let aa = { 14 user:"筱月", 15 fn:function(e,d,f){ 16 console.log(this.user); //筱月 17 console.log(e,d,f); //10 1 2 18 } 19 } 20 21 let bb = aa.fn; 22 let cc = bb.bind(aa,10); // 可以添加參數 23 cc(1,2); // 執行的時候可以繼續添加參數
總結: call 和 apply 都是改變上下文中的 this 並立即執行這個函數,bind 方法可以讓對應的函數想什么時候調就什么時候調用,並且可以將參數在執行的時候添加,這是它們的區別
let _this = this
這里就將外部的 this 放進 callback 里面,callback 里面就可以使用外部的 this
var a = function(){ } 和function b(){ } 有什么區別
function b(){} 為函數聲明,程序運行前就已存在;
var a = function(){} 為函數表達式,屬於按順序執行,所以a為undefined
1 //代碼一: 2 3 a(1); //執行這個會報錯 4 5 var a = function(index){ 6 7 alert(index); 8 9 } 10 11 a(2); //執行這個不會報錯
1 //代碼二: 2 3 a(1); //執行這個不會報錯 4 5 function a(index){ 6 7 alert(index); 8 9 } 10 11 a(2); //執行這個不會報錯