全棧(全站)開發工程師(FULL-STACK):先後端本身均可以獨立完成開發javascript
須要使用的技術棧:php
[前端]css
HTML(5) + CSS(3)html
JAVASCRIPT(JQ、VUE、REACT...)前端
[後端]vue
Java (JSP)(最難)html5
Pythonjava
Nodenode
PHP (PHP)mysql
C# (.net ->dot net) (ASP.NET)
C
...
[數據庫]
mysql
sql server
oracle(最難數據分析、數據挖掘就是用的這個)
mongodb (和node結合緊密的)
...
[自動化]
git / svn
webpack (基於NODE運行的)
服務器部署工具 iis/apache/nginx...
linux操做系統
insights.stackoverflow.com/survey/2016
前端:客戶
後端:服務器端
所謂的全棧,實際上是你能夠實現客戶端和服務器端程序的編寫,並且還能夠實現兩端之間的通訊
客戶端和服務器端是如何通訊的?
職業規劃建議:
培養本身的人脈圈,以及創建本身的影響力
一、壯大本身的綜合能力
二、常常參加一些活動
三、開放分享(作講師分享本身的智慧、寫本身的我的博客作技術分享)
...
本身作一個技術博客
一、本地開發(當前項目能夠在本地預覽)
二、部署到服務器上,讓別人能夠經過域名或者外網訪問
- 購買域名
- 把本身作的項目傳到服務器上
- 讓域名和服務器關聯(DNS解析:域名解析)
- 在服務器上發佈或者部署咱們的項目(iis、nginx、apache...)
三、作一些推廣(SEO推廣、友情連接交換、技術文章持續更新...)
客戶端和服務器端的交互(通訊)模型:
經過域名找到服務器,經過端口號才能找到服務器裏面具體的對應項目(服務器裏面能夠放多個項目),一臺服務器的端口號是0~65535之間
能夠參考iis部署(比較簡單,可是通常用nginx)
使用FileZilla進行FTP上傳:
假設咱們訪問的是 https://www.baidu.com/
這個地址,按下ENTER鍵後,咱們能夠看到百度首頁面:
百度頁面並無在咱們本身的客戶端本地,咱們是輸入地址後,才請求過來的
輸入不一樣的域名能夠看到不一樣的頁面
有的網址是https,有的是http(也有的是ftp)
須要客戶端聯網才能完成這些事情
...
都經歷哪些事情?(參考以上:客戶端和服務器端的交互(通訊)模型的圖)
[Request 客戶端的請求階段]
一、首先根據客戶端輸入的域名,到DNS服務器上進行反解析(經過域名找到對應服務器的外網IP)
二、經過找到的外網IP,找到對應的服務器
三、經過在地址欄中輸入的端口號(沒輸入是由於不一樣協議有本身默認端口號)找到服務器上發佈的對應的項目
[Response 服務器端響應階段]
四、服務器獲取到請求資源文件的地址 例如:/stu/index.html
,把資源文件中的**原代碼
**找到
五、服務器端會把找到的原代碼返回給客戶端(經過HTTP等傳輸協議返回的)
[客戶端瀏覽器自主渲染]
六、客戶端接收到原代碼後,會交給瀏覽器的內核(渲染引擎)進行渲染,最後由瀏覽器繪製出對應的頁面
cmd 輸入 ipconfig -all 查看電腦ip地址
iis部署操做如圖
手機也能夠經過這個地址(ip+端口)進行訪問
客戶端和服務器端的交互(通訊)模型:
見=>經典面試題:當咱們在瀏覽器地址欄中輸入一個URL地址,到最後看到頁面,中間都經歷了哪些事情?
URI:統一資源標識符
URL:統一資源路徑地址
URN:統一資源名稱
URI = URL + URN
www.html5train.com/stu/index.h…
問號後面的值都是傳給服務器的,服務器也能夠把這些值拿到而且返回內容
第一部分:傳輸協議
傳輸協議是用來完成客戶端和服務器端的數據(內容)傳輸的,相似於快遞小哥,負責把客戶和商家的物品來回傳送
一、客戶端不只能夠向服務器發送請求,並且還能夠把一些內容傳遞給服務器 (好比問號後面的值都是傳給服務器的)
二、服務器端也能夠把內容返回給客戶端
客戶端和服務器端傳輸的內容總稱HTTP報文,這些報文信息都是基於傳輸協議完成傳輸的,客戶端傳遞給服務器叫作請求(request),服務器返回給客戶端叫作響應(response),request+response兩個階段統稱爲一個HTTP事務(事務:一件完整的事情)
HTTP事務:
一、當客戶端向服務器端發送請求,此時客戶端和服務器端會創建一個傳輸通道(連接通道),傳輸協議就是基於這個通道把信息進行傳輸的
二、當服務器端接受到請求信息,把內容返回給客戶端後,傳輸通道會自動銷燬關閉
傳輸協議分類:
http:超文本傳輸協議(客戶端和服務器端傳輸的內容除了文本之外,還能夠傳輸圖片、音視頻等文件流[二進制編碼/BASE64碼],以及傳輸xml格式的數據等),是目前市場上應用最廣範的傳輸協議
https:http ssl,它比http更加安全,由於數據內容的傳輸通道是通過ssl加密的(它須要在服務器端進行特殊的處理),因此涉及資金類的網站通常都是https協議的
ftp:資源文件傳輸協議,通常用於客戶端把資源文件(不是代碼)上傳到服務器端,或者從服務器端下載一些資源文件(通常ftp傳輸的內容會比http這類協議傳輸的內容多)
...
HTTP報文:
一、起始行
請求起始行
響應起始行
二、首部(頭)
請求頭:內置請求頭、自定義請求頭
響應頭:內置響應頭、自定義響應頭
通用頭:請求和響應都有的
三、主體
請求主體
響應主體
請求XXX都是客戶端設置的信息,服務器端獲取這些信息
響應XXX都是服務器端設置的信息,客戶端用來接收這些信息
在谷歌瀏覽器控制檯Network選項中,咱們能夠看見當前客戶端和服務器端交互的所有信息
總結:
客戶端傳遞給服務器端數據
一、URL問號傳遞參數
二、設置請求頭(內置請求頭、自定義請求頭)
三、設置請求主體
...
服務器端返回給客戶端內容
一、設置響應頭(例如服務器時間)
二、設置響應主體
...
第二部分:域名
設置域名其實就給很差記憶的服務器外網IP設置了一個好記憶的名字
頂級域名(一級域名):qq.com
二級域名:www.qq.com、v.qq.com、sports.qq.com ...
三級域名:kbs.sports.qq.com
...
第三部分:端口號
在服務器發佈項目的時候,咱們能夠經過端口號區分當前服務器上不一樣的項目
一臺服務器的端口號取值範圍:0~65535之間,若是電腦上安裝了不少程序,有一些端口號是被佔用了
HTTP:默認端口號80
HTTPS:默認端口號443
FTP:默認端口號21
對於上述三個端口號實際上是很重要的,若是被其它程序佔用,咱們則不能使用了;因此服務器上通常是禁止安裝其它程序的;
第四部分:請求資源文件的路徑名稱
/stu/index.html
在服務器中發佈項目的時候,咱們通常都會配置一些默認文檔:用戶即便不輸入請求文件的名稱,服務器也會找到默認文檔(通常默認文檔都是index/default...)
咱們一般爲了作SEO優化,會把一些動態頁面的地址(xxx.php、xxx.aspx、xxx.asp、xxx.jsp...)進行僞URL重寫(須要服務器處理的)
item.jd.com/4325427.htm… 不多是有一個商品,本身就單獨寫一個詳情頁面,確定是同一個詳情頁作的不一樣處理
1)第一種方案:
由後臺語言根據詳情頁模板動態生成具體的詳情頁面
2)第二種方案:
當前頁面就是一個頁面,例如:detail.html(先後端徹底分離) / detail.php(不是先後端徹底分離)...,咱們作詳情頁面的時候,開發是按照 detail.html?id=4325427 來開發的;可是這種頁面不方便作SEO優化,此時咱們把真實的地址進行重寫,重寫爲咱們看到的 4325427.html
第五部分:問號傳參
?name=zf&age=9....
把一些值經過xxx=xxx的方式,放在一個URL的末尾,經過問號傳遞
[做用]
一、在AJAX請求中,咱們能夠經過問號傳遞參數的方式,客戶端把一些信息傳遞給服務器,服務器根據傳遞信息的不同,返回不一樣的數據
//=>$.ajax(url,{});
//=>$.get(url,function(){}); 對於AJAX請求的特殊寫法,原理仍是基於AJAX方法實現的 $.post / $.script ...
$.ajax({
url:'getPersonInfo?id=12'
...
});
//=>當前案例,咱們傳遞給服務器的編號是多少,服務器端就會把對應編號人員信息給返回
複製代碼
二、消除AJAX請求中GET方式緩存
$.ajax({
url:'xxx?_=0.123456',
method:'get'
});
//=>咱們會在請求URL的末尾追加一個隨機數 _=隨機數,保證每一次請求的URL都是不同的,以此來消除GET請求遺留的緩存問題
複製代碼
三、經過URL傳遞參數的方式,能夠實現頁面之間信息的通訊,例如:咱們有兩個頁面A/B,A是列表頁面,B是詳情頁,點擊A中的某一條信息,進入到惟一的詳情頁B,如何展現不一樣的信息,這種操做就能夠基於URL問號傳遞參數來實現了
例如:
在進入到game.htm頁面的時候,咱們能夠獲取URL傳遞的參數值,根據傳遞參數值的不同,從服務器端獲取不一樣的數據展現
在列表頁面進行頁面跳轉的時候,咱們須要記住的是跳轉的同時傳遞不一樣的參數值
<a href='game.html?mid=xxxx'>
複製代碼
除了問號傳參能夠實現頁面之間信息的通訊之外,還有什麼方式能夠實現頁面之間的通訊
問號傳參:(經常使用)
本地存儲:A頁面裏面把一些信息存到本地,B頁面當中能夠從本地把這些信息拿到(好比登陸、註冊成功以後其餘頁面要獲取到用戶的信息)
iframe:把一個頁面看成當前頁面的子頁面嵌套到當前頁面中,這個頁面就能夠獲取到這個嵌套頁面中的信息了
第六部分:HASH值
#xxx
URL末尾傳遞的井號什麼,就是HASH值(哈希值)
[做用]
一、頁面中錨點定位
二、前端路由(SPA單頁面開發)
頁面中每發送一次HTTP請求,都須要完成請求+響應這個完整的HTTP事務,會消耗一些時間,也可能會致使HTTP連接通道的堵塞,爲了提升頁面加載速度和運行的性能,咱們應該減小HTTP的請求次數和減小請求內容的大小(請求的內容越大,消耗的時間越長)
瀏覽器在一行行解析服務器返回的內容時,解析html須要發送一次http請求,每解析html中的link,script,img標籤時須要發送http請求(從這些方面去考慮)
一、採用CSS雪碧圖(CSS Sprit / CSS 圖片精靈)技術,把一些小圖合併在一張大圖上,使用的時候經過背景圖片定位,定位到具體的某一張小圖上
//css
.pubBg{
background:url('../img/sprit.png') no-repeat;//只須要發送一次http請求
background-size:x y; /*和原圖的大小保持一致*/
}
.box{
background-position:x y; /*經過背景定位,定位到具體的位置,展現不一樣的圖片便可*/
}
//html
<div class='pubBg box'></div>
複製代碼
二、真實項目中,咱們最好把CSS或者JS文件進行合併壓縮;尤爲是在移動端開發的時候,若是CSS或者JS內容不是不少,咱們能夠採起內嵌式,以此減小HTTP請求的次數,加快頁面加載速度;
1)CSS合併成一個,JS也最好合併成一個
2)首先同過一些工具(例如:webpack)把合併後的CSS或者JS壓縮成 xxx.min.js,減小文件大小
3)服務器端開啓資源文件的GZIP壓縮
...
經過一些自動化工具完成CSS以及JS的合併壓縮,或者再完成LESS轉CSS,ES6轉ES5等操做,咱們把這種自動化構建模式,稱之爲前端「工程化」開發
三、採用圖片懶加載技術,在頁面開始加載的時候,不請求真實的圖片地址,而是用默認圖佔位,當頁面加載完成後,在根據相關的條件依次加載真實圖片(減小頁面首次加載HTTP請求的次數)
真實項目中,咱們開始圖片都不加載,頁面首次加載完成,先把第一屏幕中能夠看見的圖片進行加載,隨着頁面滾動,在把下面區域中可以呈現出來的圖片進行加載
根據圖片懶加載技術,咱們還能夠擴充出,數據的懶加載
1)開始加載頁面的時候,咱們只把首屏或者前兩屏的數據從服務器端進行請求(有些網站首屏數據是後臺渲染好,總體返回給客戶端呈現的)
有些網站的首屏數據多是服務器給你渲染好返回過來的,也有多是服務器返回的就是一個完整的html、css(服務器給你返回的不是json格式數據了,而是一個完整html文檔,客戶端只須要展現就好了)可是服務器渲染有個弊端就是壓力大,可是比客戶端渲染快(客戶端向服務器端發送請求,服務器端把全部數據拿到,把這些數據經過html、css拼接成字符串,能夠直接渲染到頁面中,也能夠經過ajax的方式以文檔的形式返回,而後客戶端在頁面中呈現,減小了客戶端本身綁定數據的過程)
像京東、淘寶首屏通常就是服務器端渲染加載的,第二屏多是客戶端進行渲染,無論是客戶端渲染仍是服務器端渲染,剛開始只是把首屏或者前兩屏的數據從服務器端進行請求渲染出來。接下來第 2)當頁面下拉
2)當頁面下拉,滾動到哪一個區域,在把這個區域須要的數據進行請求(請求回來作數據綁定以及圖片延遲加載等)
3)分頁展現技術採用的也是數據的懶加載思想實現的:若是咱們請求獲取的數據是不少的數據,咱們最好分批請求,開始只請求第一頁的數據,當用戶點擊第二頁(微博是下拉到必定距離後,再請求第二頁數據...)的時候在請求第二頁數據...
四、對於不常常更新的數據,最好採用瀏覽器的304緩存作處理(主要由服務器端處理)
例如:
第一次請求css和js下來,瀏覽器會把請求的內容緩存起來,若是作了304處理,用戶再次請求css和js,直接從緩存中讀取,不須要再去服務器獲取了(減小了HTTP請求次數)
當用戶強制刷新頁面(CTRL+F5)或者當前緩存的CSS或者JS發生了變更,都會重新從服務器端拉取
...
對於客戶端來說,咱們還能夠基於localStorage來作一些本地存儲,例如:第一次請求的數據或者不常常更新的CSS和JS,咱們均可以把內容存儲在本地,下一次頁面加載,咱們從本地中獲取便可,咱們設定必定的期限或者一些標識,能夠控制在某個階段從新從服務器獲取
五、使用字體圖標代替一些頁面中的位圖(圖片),這樣不只作適配的時候方便,並且更加輕量級,並且減小了HTTP請求次數(相似於雪碧圖)
六、若是當前頁面中出現了AUDIO或者VIDEO標籤,咱們最好設置它們的preload=none:頁面加載的時候,音視頻資源不進行加載,播放的時候再開始加載(減小頁面首次加載HTTP請求的次數)
preload=auto:頁面首次加載的時候就把音視頻資源進行加載了
preload=metadata:頁面首次加載的時候只把音視頻資源的頭部信息進行加載
...
七、在客戶端和服務器端進行數據通訊的時候,咱們儘可能採用JSON格式進行數據傳輸
[優點]
1)JSON格式的數據,可以清晰明瞭的展現出數據結構,並且也方便咱們獲取和操做
2)相對於很早之前的XML格式傳輸,JSON格式的數據更加輕量級
3)客戶端和服務器端都支持JSON格式數據的處理,處理起來很是的方便
真實項目中,並非全部的數據都要基於JSON,咱們儘量這樣作,可是對於某些特殊需求(例如:文件流的傳輸或者文檔傳輸),使用JSON就不合適了
八、採用CDN加速
CDN:分佈式(地域分佈式)
除了減小HTTP請求次數和大小能夠優化性能,咱們在編寫代碼的時候,也能夠進行一些優化,讓頁面的性能有所提高(有些很差的代碼編寫習慣,會致使頁面性能消耗太大,例如:內存泄漏)
一、在編寫JS代碼的時候,儘可能減小對DOM的操做(VUE和REACT框架在這方面處理的很是不錯)
在JS中操做DOM是一個很是消耗性能的事情,可是咱們又不可避免的操做DOM,咱們只能儘可能減小對於它的操做
[操做DOM弊端]
1)DOM存在映射機制(JS中的DOM元素對象和頁面中的DOM結構是存在映射機制的,一改則都改),這種映射機制,是瀏覽器按照W3C標準完成對JS語言的構建和DOM的構建(其實就是構建了一個監聽機制),操做DOM是同時要修改兩個地方,相對於一些其它的JS編程來講是消耗性能的
2)頁面中的DOM結構改變或者樣式改變,會觸發瀏覽器的迴流(瀏覽器會把DOM結構從新進行計算,這個操做很耗性能)和重繪(把一個元素的樣式從新渲染)
...
二、編寫代碼的時候,更多的使用異步編程
同步編程會致使:上面東西完不成,下面任務也作不了,咱們開發的時候,能夠把某一個區域模塊都設置爲異步編程,這樣只要模塊之間沒有必然的前後順序,均可以獨立進行加載,不會受到上面模塊的堵塞影響(用的很少)
尤爲是AJAX數據請求,咱們通常都要使用異步編程,最好是基於promise設計模式進行管理(項目中常用 fetch、vue axios 等插件來進行AJAX請求處理,由於這些插件中就是基於promise設計模式對ajax進行的封裝處理)
三、在真實項目中,咱們儘量避免一次性循環過多數據(由於循環操做是同步編程),尤爲是要避免while致使的死循環操做
四、CSS選擇器優化
1)儘可能減小標籤選擇器的使用
2)儘量少使用ID選擇器,多使用樣式類選擇器(通用性強)
3)減小選擇器前面的前綴,例如:.headerBox .nav .left a{ } (選擇器是從右向左查找的)=> 起名字的時候作優化.header-nav-left a{}
...
五、避免使用CSS表達式
/*CSS表達式*/
.box{
background-color:expression((new Date()).getHours()%2?'red':'blue')
}
複製代碼
六、減小頁面中的冗餘代碼,儘量提升方法的重複使用率:「低耦合高內聚」 => 也是類封裝的目的
七、最好CSS放在HEAD中,JS放在BODY尾部,讓頁面加載的時候,先加載CSS,在加載JS(先呈現頁面,在給用戶提供操做)
八、JS中避免使用eval
1)性能消耗大
2)代碼壓縮後,容易出現代碼執行錯亂問題
九、JS中儘可能減小閉包的使用
1)閉包會造成一個不銷燬的棧內存,過多的棧內存累積會影響頁面的性能
2)還會容易致使內存的泄漏
閉包也有本身的優點:保存和保護,咱們只能儘可能減小,可是無可避免
十、在作DOM事件綁定的時候,儘可能避免一個個的事件綁定,而是採用性能更高的事件委託來實現
事件委託(事件代理)
把事件綁定給外層容器,當裏面的後代元素相關行爲被觸發,外層容器綁定的方法也會被觸發執行(冒泡傳播機制致使),經過事件源是誰,咱們作不一樣的操做便可
十一、儘可能使用CSS3動畫代替JS動畫,由於CSS3的動畫或者變形都開啓了硬件加速,性能比JS動畫好
十二、編寫JS代碼的時候儘量使用設計模式來構建體系,方便後期的維護,也提升了擴充性等
1三、CSS中減小對濾鏡的使用,頁面中也減小對於FLASH的使用
一、頁面中杜絕出現死連接(404頁面),並且對於用戶輸入一個錯誤頁面,咱們要引導到404提示頁面中(服務器處理的)
二、避免瀏覽器中異常錯誤的拋出
儘量避免代碼出錯
使用TRY CATCH作異常信息捕獲
...
三、增長頁面關鍵詞優化
見WEEK8-1-BASE面試題彙總
什麼是AJAX?
async javascript and xml,異步的JS和XML
xml:可擴展的標記語言
做用是用來存儲數據的(經過本身擴展的標記名稱清晰的展現出數據結構)以下:
WEEK8-temp.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<student>
<name>張三</name>
<age>25</age>
<score>
<english>90</english>
<math>100</math>
<chinese>98</chinese>
</score>
</student>
<student>
<name>李四</name>
<age>24</age>
<score>
<english>80</english>
<math>90</math>
<chinese>100</chinese>
</score>
</student>
</root>
複製代碼
ajax之因此稱爲異步的js和xml,主要緣由是:當初最開始用ajax實現客戶端和服務器端數據通訊的時候,傳輸的數據格式通常都是xml格式的數據,咱們咱們把它稱之爲異步js和xml(如今通常都是基於JSON格式來進行數據傳輸的)
異步的JS
這裏的異步不是說ajax只能基於異步進行請求(雖然建議都是使用異步編程),這裏的異步特指的是 「局部刷新」
局部刷新 VS 全局刷新
在非徹底先後端分離項目中,前端開發只須要完成頁面的製做,而且把一些基礎的人機交互效果使用js完成便可,頁面中須要動態呈現內容的部分,都是交給後臺開發工程師作數據綁定和基於服務器進行渲染的(服務器端渲染)
[優點]
一、動態展現的數據在頁面的原代碼中能夠看見,有利於SEO優化推廣(有利於搜索引擎的收錄和抓取)
二、從服務器端獲取的結果就已是最後要呈現的結果了,不須要客戶端作額外的事情,因此頁面加載速度快(前提是服務器端處理的速度夠快,可以處理過來),因此相似於京東、淘寶這些網站,首屏數據通常都是經由服務器端渲染的
[弊端]
一、若是頁面中存在須要實時更新的數據,每一次想要展現最新的數據,頁面都要從新的刷新一次,這樣確定不行
二、都交給服務器端作數據渲染,服務器端的壓力太大,若是服務器處理不過來,頁面呈現的速度更慢(因此京東淘寶這類網站,除了首屏是服務器端渲染的,其它屏通常都是客戶端作數據渲染綁定)
三、這種模式不利於開發(開發效率低)
非徹底先後端分離如圖:
目前市場上大部分項目都是先後端徹底分離的項目(也有非徹底先後端分離的)
先後端徹底分離的項目,頁面中須要動態綁定的數據是交給客戶端完成渲染的
一、向服務器端發送AJAX請求
二、把從服務器端獲取的數據解析處理,拼接成爲咱們須要展現的HTML字符串
三、把拼接好的字符串替換頁面中某一部分的內容(局部刷新),頁面總體不須要從新加載,局部渲染便可
[優點]
一、咱們能夠根據需求,任意修改頁面中某一部分的內容(例如實時刷新),總體頁面不刷新,性能好,體驗好(全部表單驗證、須要實時刷新的等需求都要基於AJAX實現)
二、有利於開發,提升開發的效率
1)先後端的徹底分離,後臺不須要考慮前端如何實現,前端也不須要考慮後臺用什麼技術,真正意義上實現了技術的劃分
2)能夠同時進行開發:項目開發開始,首先制定先後端數據交互的接口文檔(文檔中包含了,調取哪一個接口或者哪些數據等協議規範),後臺把接口先寫好(目前不少公司也須要前端本身拿NODE來模擬這些接口),客戶端按照接口調取便可,後臺再次去實現接口功能便可
[弊端]
一、不利於SEO優化:第一次從服務器端獲取的內容不包含須要動態綁定的數據,因此頁面的源代碼中沒有這些內容,不利於SEO收錄,後期經過JS添加到頁面中的內容,並不會寫在頁面的源代碼中(是源代碼不是頁面結構)
二、交由客戶端渲染,首先須要把頁面呈現,而後再經過JS的異步AJAX請求獲取數據,而後數據綁定,瀏覽器在把動態增長的部分從新渲染,無形中浪費了一些時間,沒有服務器端渲染頁面呈現速度快
先後端徹底分離:
//=>建立一個AJAX對象
let xhr=new XMLHttpRequest();//=>不兼容IE6及更低版本瀏覽器(IE6:ActiveXObject)
//=>打開請求地址(能夠理解爲一些基礎配置,可是並無發送請求呢)
xhr.open([method],[url],[async],[user name],[user password]);
//=>監聽AJAX狀態改變,獲取響應信息(獲取響應頭信息、獲取響應主體信息)
xhr.onreadystatechange=()=>{
if(xhr.readyState===4 && xhr.status===200){
let result=xhr.responseText;//=>獲取響應主體中的內容
}
};
//=>發送AJAX請求(括號中傳遞的內容就是請求主體的內容)
xhr.send(null);
複製代碼
分析第二步中的細節點
xhr.open([method],[url],[async],[user name],[user password])
[AJAX請求方式]
一、GET系列的請求(獲取)
get
delete:從服務器上刪除某些資源文件
head:只想獲取服務器返回的響應頭信息(響應主體內容不須要獲取)
...
二、POST系列請求(推送)
post
put:向服務器中增長指定的資源文件
...
無論哪種請求方式,客戶端均可以把信息傳遞給服務器,服務器也能夠把信息返回給客戶端,只是GET系列通常以獲取爲主(給的少,拿回來的多),而POST系列通常以推送爲主(給的多,拿回來的少)
1)咱們想獲取一些動態展現的信息,通常使用GET請求,由於只須要向服務器端發送請求,告訴服務器端咱們想要什麼,服務器端就會把須要的數據返回
2)在實現註冊功能的時候,咱們須要把客戶輸入的信息發送給服務器進行存儲,服務器通常返回成功仍是失敗等狀態,此時咱們通常都是基於POST請求完成
...
一、GET請求傳遞給服務器的內容通常沒有POST請求傳遞給服務器的內容多
緣由:GET請求傳遞給服務器內容通常都是基於url地址問號傳遞參數來實現的,而POST請求通常都是基於設置請求主體來實現的。
各瀏覽器都有本身的關於URL最大長度的限制(谷歌:8KB、火狐:7KB、IE:2KB...)超過限制長度的部分,瀏覽器會自動截取掉,致使傳遞給服務器的數據缺失。
理論上POST請求經過請求主體傳遞是沒有大小限制的,真實項目中爲了保證傳輸的速率,咱們也會限制大小(例如:上傳的資料或者圖片咱們會作大小的限制)
二、GET請求很容易出現緩存(這個緩存不可控:通常咱們都不須要),而POST不會出現緩存(除非本身作特殊處理)
緣由:GET是經過URL問號傳參傳遞給服務器信息,而POST是設置請求主體;
設置請求主體不會出現緩存,可是URL傳遞參數就會了。
//=>每一個一分鐘重新請求服務器端最新的數據,而後展現在頁面中(頁面中某些數據實時刷新)
setTimeout(()=>{
$.ajax({
url:'getList?lx=news',
...
success:result=>{
//=>第一次請求數據回來,間隔一分鐘後,瀏覽器又發送一次請求,可是新發送的請求,無論是地址仍是傳遞的參數都和第一次同樣,瀏覽器頗有可能會把上一次數據獲取,而不是獲取最新的數據
}
});
},60000);
//=>解決方案:每一次從新請求的時候,在URL的末尾追加一個隨機數,保證每一次請求的地址不徹底一致,就能夠避免是從緩存中讀取的數據
setTimeout(()=>{
$.ajax({
url:'getList?lx=news&_='+Math.random(),
...
success:result=>{}
});
},60000);
複製代碼
三、GET請求沒有POST請求安全(POST也並非十分安全,只是相對安全)
緣由:仍是由於GET是URL傳參給服務器
有一種比較簡單的黑客技術:URL劫持,也就是能夠把客戶端傳遞給服務器的數據劫持掉,致使信息泄露
URL:請求數據的地址(API地址),真實項目中,後臺開發工程師會編寫一個API文檔,在API文檔中彙總了獲取哪些數據須要使用哪些地址,咱們按照文檔操做便可
ASYNC:異步(SYNC同步),設置當前AJAX請求是異步的仍是同步的,不寫默認是異步(TRUE),若是設置爲FALSE,則表明當前請求是同步的
用戶名和密碼:這兩個參數通常不用,若是你請求的URL地址所在的服務器設定了訪問權限,則須要咱們提供可通行的用戶名和密碼才能夠(通常服務器都是能夠容許匿名訪問的)
第三部分細節研究
//=>監聽AJAX狀態改變,獲取響應信息(獲取響應頭信息、獲取響應主體信息)
xhr.onreadystatechange=()=>{
if(xhr.readyState===4 && xhr.status===200){
let result=xhr.responseText;//=>獲取響應主體中的內容
}
};
複製代碼
AJAX狀態碼:描述當前AJAX操做的狀態的
xhr.readyState
0:UNSENT 未發送,只要建立一個AJAX對象,默認值就是零
1:OPENED 咱們已經執行了xhr.open這個操做
2:HEADERS_RECEIVED 當前AJAX的請求已經發送,而且已經接收到服務器端返回的響應頭信息了
3:LOADING 響應主體內容正在返回的路上
4:DONE 響應主體內容已經返回到客戶端
...
HTTP網絡狀態碼:記錄了當前服務器返回信息的狀態 xhr.status
200:成功,一個完整的HTTP事務完成(以2開頭的狀態碼通常都是成功)
以3開頭通常也是成功,只不過服務器端作了不少特殊的處理
301:Moved Permanently 永久轉移(永久重定向)通常應用於域名遷移
302:Move temporarily 臨時轉移(臨時重定向,新的HTTP版本中任務307是臨時重定向)通常用於服務器的負載均衡:當前服務器處理不了,我把當前請求臨時交給其餘的服務器處理(通常圖片請求常常出現302,不少公司都有單獨的圖片服務器)
304:Not Modified 從瀏覽器緩存中獲取數據 把一些不常常更新的文件或者內容緩存到瀏覽器中,下一次從緩存中獲取,減輕服務器壓力,也提升頁面加載速度
以4開頭的,通常都是失敗,並且客戶端的問題偏大
400:請求參數錯誤
401:無權限訪問
404:訪問地址不存在
以5開頭的,通常都是失敗,並且服務器的問題偏大
500:Internal Server Error 未知的服務器錯誤
503:Service Unavailable 服務器超負載(作不了負載均衡) ...
面試題:AJAX中總共支持幾個方法?
let xhr = new XMLHttpRequest();
console.dir(xhr);
複製代碼
readyState:存儲的是的當前ajax的狀態碼
response/responseText/responseXML:都是用來接收服務器返回的相應主體中的內容,只是根據服務器返回的內容的格式不同,咱們使用不一樣的屬性接收便可
responseText是最經常使用的,接收的結果是字符串格式的(通常服務器返回的數據都是json格式字符串)
responseXML偶爾會用到,若是服務器端返回的是xml文檔數據,咱們須要使用這個屬性接收
status:記錄了服務器端返回的http狀態碼
statusText:對返回狀態碼的描述
timeout:設置當前ajax請求的超時時間,假設咱們設置時間爲3000ms,從ajax請求發送開始,3秒後響應主體內容尚未返回,瀏覽器會把當前ajax請求任務強制斷開
[方法]
about():強制中斷ajax請求
getAllResponseHeaders():獲取所有的響應頭信息(獲取的結果是一堆字符串文本)
getResponseHeader():獲取指定屬性名的響應頭信息,例如:xhr.getResponseHeader('date')獲取響應頭中存儲的服務器的時間
open():打開一個url地址
overrideMimeType():重寫數據的MIME類型
send():發送ajax請求(括號中書寫的內容時客戶端基於請求主體把信息傳遞給服務器)
setRequestHeader(key,value):設置請求頭信息(能夠是設置的自定義請求頭信息)
[事件]
onabort:當ajax被中斷請求觸發這個事件
onreadystatechange:ajax狀態發生改變,會觸發這個事件
ontimeout:當ajax請求超時,會觸發這個事件
...
WEEK8-2-AJAX-1-ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="1.js"></script>
</body>
</html>
複製代碼
WEEK8-2-AJAX-1.js
let xhr = new XMLHttpRequest();
// xhr.setRequestHeader('aaa','xxx');//設置請求頭必須在open以後和send以前
xhr.open('get','temp.json?='+Math.random().true);
xhr.open('get','temp.xml?='+Math.random().true);
// xhr.setRequestHeader('cookie','嗨');//設置的請求頭內容不是一個有效的值(請求頭部的內容中不得出現中文漢字)
xhr.setRequestHeader('aaa','xxx');
// 設置超時
xhr.timeout = 10;
xhr.ontimeout = () =>{
console.log('當前請求已經超時');
xhr.abort();
}
xhr.onreadystatechange = () => {
let {readyState:state,status} = xhr;
// 說明請求數據成功了
if(!/^(2|3)\d{2}$/.test(status)) return;
// 在狀態爲2的時候就能夠獲取響應頭信息
if (state === 2) {
let headerAll = xhr.getAllResponseHeaders(),
serverDate = xhr.getResponseHeader('date');//獲取的服務器時間是格林尼治時間(相比於北京時間差了8小時)
console.log(headerAll,new Date(serverDate));//經過new Date()能夠把這個時間轉換爲北京時間
return;
}
// 在狀態爲4的時候響應主體內容就已經回來了
if(state === 4){
let valueText = xhr.responseText,//獲取到的結果通常的都是json字符串(可使用JSON.PARSE轉換爲json對象)
valueXML = xhr.responseXML;//獲取到的結果是xml格式的數據(能夠經過xml的一些常規操做獲取存儲的指定信息)若是服務器返回的是xml文檔,
// responseText獲取的結果是字符串而responseXML獲取的是標準xml文檔
console.log(valueText,valueXML);
}
}
xhr.send('name=sjb&age=24&sex=man');
複製代碼
WEEK8-2-AJAX-temp.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<student>
<name>張三</name>
<age>25</age>
<score>
<english>90</english>
<math>100</math>
<chinese>98</chinese>
</score>
</student>
<student>
<name>李四</name>
<age>24</age>
<score>
<english>80</english>
<math>90</math>
<chinese>100</chinese>
</score>
</student>
</root>
複製代碼
WEEK8-2-AJAX-temp.json
[
{
"name":"張三",
"age":25,
"score":{
"english":95,
"math":100,
"chinese":98
}
},
{
"name":"李四",
"age":25,
"score":{
"english":95,
"math":100,
"chinese":98
}
}
]
複製代碼
正常的編碼解碼(非加密)
一、escape/unescape:主要就是把中文文字進行編碼和解碼的(通常只有js語言支持;也常常應用於前端頁面通訊時候的中文漢字編碼,好比須要把a頁面的中文數據傳遞給b頁面,b頁面拿到亂碼了,就須要在a頁面把這些中文數據信息經過escape進行編碼,b頁面中經過unescape解碼)
二、encodeURI/decodeURI:基本上全部的編程語言都支持
三、encodeURIComponent/decodeURIComponent:和第二種方式很是相似,區別在於
需求:咱們URL問號傳遞參數的時候,咱們傳遞的參數值仍是一個url或者包含不少特殊的字符,此時爲了避免影響主要的url,咱們須要把傳遞的參數值進行編碼。使用encodeURI不能編碼一些特殊字符,因此只能使用encodeURIComponent處理
let str = 'http://www.baidu.com/?',
obj = {
name:'嗨嗨嗨',
age:9,
url:'http://www.1626.com/?lx=1'
};
// 把obj中的每一項屬性名和屬性值拼接到url的末尾(問號傳參方式)
for(let key in obj){
str+=`${key}=${encodeURIComponent(obj[key])}&`;
// 不能使用encodeURI,必須使用encodeURIComponent,緣由是encodeURI不能編碼特殊的字符
}
console.log(str.replace(/&$/g,''));
// 後期獲取url問號參數的時候,咱們把獲取的值在依次解碼便可
String.prototype.myQueryUrlParameter=function myQueryUrlParameter(){
let reg=/[?&]([^?&=]+)(?:=([^?&=]*))?/g,
obj={};
this.replace(reg,(...arg)=>{
let [,key,value]=arg;
obj[key]=decodeURIComponent(value);//此處獲取的時候能夠進行解碼
});
return obj;
}
複製代碼
也能夠經過加密的方法進行編碼解碼
一、可逆轉加密(通常都是團隊本身玩的規則)
二、不可逆轉加密(通常都是基於MD5加密完成的,md5加密後的結果沒有什麼規則能夠把它解密,可能會把MD5加密後的結果二次加密)密碼就是隻能加密不能解密的,就會用md5來加密密碼的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="md5.min.js"></script>
</body>
</html>
複製代碼
AJAX這個任務:發送請求接收到響應主題內容(完成一個完整的HTTP事務)
xhr.send():任務開始
xhr.readyState===4:任務結束
同步:
let xhr = new XMLHttpRequest();
xhr.open('get','temp.json',false);
xhr.onreadystatechange = () => {
console.log(xhr.readyState);
};
xhr.send();
// 只輸出一次結果是4
複製代碼
let xhr = new XMLHttpRequest();
xhr.open('get','temp.json',false);
xhr.send();//[同步]開始發送ajax請求,開啓ajax任務,在任務沒有完成以前,什麼事情都作不了(下面綁定事件也作不了)=> loading
// => 當readyState===4的時候ajaxj任務完成,開始執行下面的操做
// readyState===4
xhr.onreadystatechange = () => {
console.log(xhr.readyState);
};
// 綁定方法以前狀態已經爲4了,此時ajax的狀態不會在改變成其餘值了,因此事件永遠不會被觸發,一次都沒執行方法(使用
// ajax同步編程,不要把send放在事件監聽前,這樣咱們沒法在綁定的方法中獲取到響應主體的內容)
複製代碼
異步:
let xhr = new XMLHttpRequest();
xhr.open('get','temp.json');
xhr.onreadystatechange = () => {
console.log(xhr.readyState);
};
xhr.send();
// 輸出3次,結果分別是2 3 4
複製代碼
let xhr = new XMLHttpRequest();
xhr.open('get','temp.json');
xhr.send();
// xhr.readyState===1
xhr.onreadystatechange = () => {
console.log(xhr.readyState);
};
// 輸出3次,結果分別是2 3 4
複製代碼
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
console.log(xhr.readyState);
};
xhr.open('get','temp.json');
xhr.send();
// 1 2 3 4
複製代碼
將以上代碼改爲同步
let xhr = new XMLHttpRequest();
// xhr.readyState===0
xhr.onreadystatechange = () => {
console.log(xhr.readyState);
};
xhr.open('get','temp.json',false);
// xhr.readyState===1 ajax特殊處理的一件事,執行open狀態變爲1,會主動把以前
// 監聽的方法執行一次,而後再去執行send
xhr.send();
// xhr.readyState===4 ajax任務結束,主任務隊列完成
// 1 4
複製代碼
ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id='box'></div>
<script src="3.js"></script>
</body>
</html>
複製代碼
3.js
~function(){
let box = document.getElementById('box'),
serverTime = null;
let fn = () => {
//一、 計算當前時間和目標時間的差值
// let nowTime = new Date(),//獲取的是客戶端本機時間(會受到客戶端本身調整時間的影響),重要的事件參考不能基於這個完成,無論是哪個
// // 客戶端都須要基於相同的服務器時間計算
// let nowTime = serverTime,
//每間隔1s中,咱們須要把第一次獲取的服務器時間進行累加
serverTime = serverTime +1000;
let tarTime = new Date('2018/12/1 9:29:00').getTime(),//2017/12/14 斜槓在ie下才能轉換 中槓在ie下不能轉換 這裏用斜槓
// spanTime = tarTime - nowTime;
spanTime = tarTime - serverTime;
//二、 計算差值中包含多少時分秒
if(spanTime<0){
// 已經錯過了搶購的事件(已經開槍了)
box.innerHTML = '開槍';
clearInterval(autoTimer);
return;
}
let hours = Math.floor(spanTime/(1000*60*60));
spanTime -= hours * 3600000;
let minus = Math.floor(spanTime/(1000*60));
spanTime -= minus * 60000;
let seconds = Math.floor(spanTime/1000);
hours<10?hours='0'+hours:null;
minus<10?minus='0'+minus:null;
seconds<10?seconds='0'+seconds:null;
box.innerHTML=`距離開槍還剩下${hours}:${minus}:${seconds}`;
};
let autoTimer = setInterval(fn,1000);
// 從服務器端獲取服務器時間
let getServerTime = () => {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = ()=>{
console.log(xhr.readyState);//head請求方式,狀態碼中沒有3(由於不須要等待響應主體內容)
if(!/^(2|3)\d{2}$/.test(xhr.status)) return;
if(xhr.readyState===2){
serverTime = new Date(xhr.getResponseHeader('date')).getTime();
fn();
}
}
xhr.open('head','temp.xml',true);//head請求比get請求快,get請求包含主題內容,head不用獲取主題內容
xhr.send(null);
// 獲取服務器時間總會出現時間差的問題:服務器端把時間記錄好,到客戶端獲取到時間有延遲差(服務器返回的時候記錄的是10:00,
// 咱們客戶端獲取的時候已是10:01,可是咱們獲取的結果依然是10:00,這樣就有1分鐘時間差)
// [儘量的減小時間差,是咱們優化的所有目的]
// 一、服務器返回的時間在響應頭信息中就有,咱們只須要獲取響應頭信息便可,不必獲取響應主體內容,
// 因此請求方式使用 head 便可
// 二、必須使用異步編程:同步編程咱們沒法再狀態爲2或者3的時候作一些處理,而咱們獲取響應頭信息,在狀態爲2
// 的時候就能夠獲取了,因此須要使用異步
// 三、在狀態爲2的時候就把服務器時間獲取到
// ...
};
getServerTime();
}();
複製代碼
(其實想問ajax的優化技巧,就是以上代碼)
jq中的ajax使用及每個配置的做用(包含裏面的一些細節知識)
$.ajax({
url:'xxx.txt',//請求api地址
method:'get',//請求方式get/post...在老版本jq中使用的是type,使用type和method實現的是相同的效果
dataType:'json',//dataType只是咱們預設獲取結果的類型,不會影響服務器的返回(服務器端通常給咱們返回的都是json
// 格式字符串),若是咱們預設的是json,那麼類庫中將把服務器返回的字符串轉換爲json對象,若是咱們預設的是text(默認值),
// 咱們把服務器獲取的結果直接拿過來操做便可,咱們預設的值還能夠是xml等
cache:false,//設置是否清除緩存,支隊get系列請求有做用,默認是ture不清緩存,手動設置爲false,jq類庫會在請求url的末尾追加一個隨機數來清除緩存
data:null,//咱們經過data能夠把一些信息傳遞給服務器;get系列請求會把data中的內容拼接在url的末尾經過問號傳參的方式傳遞給服務器,post系列請求會把內容
// 放在請求主題中傳遞給服務器;data的值能夠設置爲兩種格式:字符串、對象,若是是字符串,設置的值是什麼傳遞給服務器的就是什麼,若是設置的是對象,jq會把對象變爲
// xxx = xxx&xxx = xxx 這樣的字符串傳遞給服務器
async:true,//設置同步或者異步,默認是true表明異步,false是同步
success:function(result){
// 當ajax請求成功(readyState===4&status是以2或者3開頭的)
// 請求成功後jq會把傳遞的回調函數執行,而且把獲取的結果當作實參傳遞給回調函數(result就是咱們從服務器端獲取的結果)
},
error:function(msg){
// 請求錯誤觸發回調函數
},
complate:function(){
// 無論請求是錯誤的仍是正確的都會觸發回調函數(它是完成的意思)
},
// ...
});
複製代碼
支持的參數
url
method/type
data
dataType
async
cache
success
...
基於構造函數的結構
~function(){
class ajaxClass {
}
window.ajax = function({
url = null,
method = 'GET',
type = 'GET',
data = null,
dataType = 'JSON',
cache = true,
async = true,
success = null
}={}){
};
}();
ajax({});
複製代碼
基於構造函數封裝ajax類庫
ajax.js
~function(){
class ajaxClass {
// 執行ajax
init(){
// this:examplenpm
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if(!/^[23]\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 4) {
let result = xhr.responseText;
// data-type處理 從服務器獲得的結果result,而dataType是把從服務器獲得的result結果進行二次處理
try {
switch (this.dataType.toUpperCase()){
case 'TEXT':
case 'HTML':
result = result;
break;
case 'JSON':
result = JSON.parse(result);
break;
case 'XML':
result = xhr.responseXML;
}
} catch (e) {
}
this.success(result);
}
};
// Data處理 若是data是對象須要轉換成字符串 若是是get請求 把data放在url末尾
if (this.data !== null) {
this.formatData();
if (this.isGET) {
this.url += this.querySymbol() + this.data;
this.data = null;
}
}
// cache緩存處理 若是當前請求是get請求(this.isGET爲true時是get請求)而且cache傳遞的是flase,須要緩存處理
// (在當前url末尾增長隨機數),因此在open發送以前 處理url
this.isGET ? this.cacheFn() : null;
xhr.open(this.method, this.url, this.async);
xhr.send(this.data);
}
// 把傳遞的對象格式data轉換爲字符串格式data
formatData() {
// this:examplenpm
// if(typeof this.data === 'object') { //這樣判斷不許確 null也是對象格式
// if(({}).toString.call(this.data) === '[object Object]') { //準確判斷 等價於
if(Object.prototype.toString.call(this.data) === '[object Object]') {
let obj = this.data,
str = ``;
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
str += `${key}=${obj[key]}&`;
}
}
// 去掉轉換成字符串拼接後的最後一個&
str = str.replace(/&$/g, '');
this.data = str;
}
}
cacheFn() {
// this:examplenpm
// if (this.cache === false) { //cache傳遞的是flase,須要緩存處理
// if (!this.cache) {//cache傳遞的是flase,須要清除緩存
// // 'xxx.html?_='+隨機數 可是問號後面可能還有參數 以下:
// // 'xxx.html?name=xxx&_='+隨機數
// // 因此須要驗證當前url裏面是否存在問號,存在問號須要加&,不存在問號就用問號
// }
!this.cache ? this.url += `${this.querySymbol()}_=${Math.random()}` : null;
}
// 驗證當前url裏面是否存在問號,存在問號須要加&,不存在問號就用問號
querySymbol() {
// this:examplenpm
return this.url.indexOf('?') > -1 ? '&' : '?';
}
}
//參數初始化 如下代碼也能夠在constructor中完成
window.ajax = function({
url = null,
method = 'GET',
type = 'GET',
data = null,
dataType = 'JSON',
cache = true,
async = true,
success = null
}={}){
// let example = new ajaxClass();//建立ajaxClass實例
// //把私有屬性掛載到實例上
// example.url = url;
// example.method = type === null ? method : type;
// example.data = data;
// example.dataType = dataType;
// example.cache = cache;
// example.async = async;
// example.success = typeof success === 'function' ? success : new Function();
// example.isGET = /^(GET|DELETE|HEAD)$/i.test(example.method);//判斷是否是get請求
// example.init();//執行實例上的init方法
// return example;
// 優化以上代碼 jquery就是這樣批量處理的
let example = new ajaxClass(),//建立ajaxClass實例
_this = example;
['url','method','data','dataType','cache','async','success'].forEach((item) => {
if (item === 'method') {
_this.method = type === null ? method : type;
return;
}
if (item === 'success') {
_this.success = typeof success === 'function' ? success : new Function();
return;
}
_this[item] = eval(item);
});
_this.isGET = /^(GET|DELETE|HEAD)$/i.test(example.method);//判斷是否是get請求
_this.init();//執行實例上的init方法
return _this;
};
}();
// ajax({});
複製代碼
ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="ajax.js"></script>
<script src="4.js"></script>
</body>
</html>
複製代碼
4.js
ajax({
url:'temp.json',
cache:false,
data: {
name:'呵呵',
age:10
},
success:result => {
console.log(result);
}
});
複製代碼