前言:從瀏覽器輸入網址到回車看到頁面的過程,面試逃不掉的一個問題,我們知道從瀏覽器輸入網址到看到頁面主要是涉及DNS解析,TCP三次握手,請求報文,響應報文,TCP4次揮手。
#首先我們先來看一下總體的訪問過程
#總體的訪問過程:首先會進行DNS解析,然后解析得到地址之后客戶端和web服務器會建立一條TCP連接,其中有一個TCP三次握手過程,當完成握手之后客戶端就會向瀏覽器發送一條請求報文,服務器然后進行響應,接著當數據傳輸完之后,服務器和客戶端有一個TCP四次揮手過程,來結束連接。
#然后我們來將過程分解一下
#dns解析流程
在瀏覽器中輸入網址回車后,首先系統會去找這個域名對應的ip,然后再根據這個ip地址查找web服務器,
這里面有個DNS解析流程
1、系統首先查找本地的DNS緩存和hosts文件信息,確認是否有www.baidu.com對應的ip地址,如果有就直接訪問
這個ip地址對應的www.baidu.com web服務器
2、如果沒有,那么系統會將解析請求發送給本機網卡指定的DNS服務器,稱為LDNS(本地dns),如果本地DNS服務器
中有域名www.baidu.com所對應的的ip地址,就會去訪問這個IP對應的web服務器,如果沒有就去請求其他DNS服務器
3、LDNS服務器會從根域名服務器開始對于域名www.baidu.com的解析,全球有13臺根服務器,根域名服務器沒有
www.baidu.com的解析記錄,有.com頂級域的解析記錄,然后把.com所對應的DNS服務器地址返回給LDNS服務器
4、LDNS獲取到.com的DNS服務器地址之后,就去.com服務器請求www.baidu.com域名的解析,.com里面也沒有www
.baidu.com域名對應的地址,但是有baidu.com域名的解析記錄,然后.com服務器將baidu.com對應的DNS服務器地址
返回給LDNS,
5、同理LDNS去找baidu.com的DNS服務器請求www.baidu.com的域名解析,然后baidu.com域名DNS服務器將www.baidu.com地址對應的IP解析記錄發送回給LDNS
6、LDNS把解析出的結果www.baidu.com對應的ip地址發送給客戶端的瀏覽器,然后也記錄到緩存中
#瀏覽器通過解析后得到的ip地址和端口號與web服務器建立一條TCP連接通道
#tcp3次握手過程
三次握手指一個TCP連接時,需要客戶端和服務器總共發送3個包
第一次握手:建立連接時,客戶端A發送syn包(syn=j)到服務器B,并進入Syn_send狀態,等待服務器B確認
第二次握手:服務器B收到syn包,必須確認客戶A的syn(ACK=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,然后服務器B進入SYN_RECV狀態
第三次握手:客戶端A收到服務器B的SYN+ACK包,向服務器B發送確認包ACK(ACK=k+1),包發送完畢,客戶端A和服務端B進入ESTABLISHED狀態,完成三次握手
#建立TCP連接時,瀏覽器向web服務器發送一條HTTP請求報文
請求報文包括:請求行,請求頭部,空白行,請求報文主體
請求行:
用來說明客戶端想要做什么,內容包括方法字段(請求方法包括:GET:請求指定資源,HEAD,請求響應報文的首部,
POST:提交數據到服務器,PUT:傳送的數據取代指定的文檔內容,DELETE:刪除Request-URI所標識的資源,MOVE:
移動)、URL字段以及HTTP協議版本(最開始的0.9版本,后來又有了1.0,1.1,2.0,其中1.1是主流)
請求頭:
通過客戶端把請求的相關信息發給服務器,內容包括媒體類型,語言類型,主機名等信息
空行:
告訴服務器空行以下內容不屬于請求頭部信息
請求報文主體:
用來說明客戶端具體想要做的事情
#有請求報文來請求服務器,就會有服務器端去響應,為響應報文
響應報文包括:狀態行,響應頭部,空白行,響應報文主體
狀態行
用來說明服務器響應客戶端的狀態,包括一些狀態碼信息:一些比較重要的狀態碼信息有:
200-ok 訪問成功
301-moved permanently 永久跳轉
403-Forbidden 禁止訪問,服務端設置了相關權限,客戶端沒有權限去訪問
404-Not Found 沒有找到訪問的頁面,客戶端請求的頁面不存在
500-Internal servr error 內部服務器錯誤
502-Bad gateway 壞的網關
503-Service Unavailble 服務不可用,服務超載或停機
504-Gateway Timeout 網關超時,沒有在特定時間內處理請求
響應頭將服務器響應的相關信息發給客戶端
空行:
告訴客戶端空行一下內容不屬于響應頭部信息
響應報文主體:
將web服務數據資源返回給客戶端
包括靜態網頁資源,動態網頁資源,和偽靜態資源
純html格式的為靜態網頁,服務端寫的什么就返回什么給客戶端
常見的靜態網頁后綴有html htm xml
以.php .js .aspx結尾的為動態網頁,以數據庫為基礎,可以實現很多功能
偽靜態網頁是通過一些技術(如rewrite重寫)將動態的URL偽裝成靜態的URL,但實際上還是動態的URL
#當完成數據傳輸之后,就會有一個四次揮手的過程來進行斷開連接
#tcp4次揮手過程
、跳轉語句
在循環控制語句中,當滿足指定條件時,退出循環或者是退出當前循環的語句
1.break
格式:break;
跳出并終止循環,如果后面有代碼,則繼續往下執行
輸出結果為0,1,2;當i==3時,break跳出語句
2.continue
格式:continue;
跳出并終止當前的循環,如果下個值仍滿足循環條件,則繼續循環
注:如果有合適的語句最好代替continue
輸出結果為0,1,2,4;當j==3時,continue跳出本次循環,j==4,繼續輸出。
二、標簽語句
用來退出多層循環
格式:
標簽名:語句;
注意:標簽名只可以作用于break 或continue
輸出結果為
當i==0;輸出“第一層循環0”換行
開始第二層循環,輸出‘第二層循環0第二層循環1第二層循環2第二層循環3’break,直接跳出到out,結束循環
三、with---不建議使用
with(document){
write("1");
write("2");
write("3");
}
今年國慶假期終于可以憋在家里了不用出門了,不用出去看后腦了,真的是一種享受。這么好的光陰怎么浪費,睡覺、吃飯、打豆豆這怎么可能(耍多了也煩),完全不符合我們程序員的作風,趕緊起來把文章寫完。
這篇文章比較基礎,在國慶期間的業余時間寫的,這幾天又完善了下,力求把更多的前端所涉及到的關于文件上傳的各種場景和應用都涵蓋了,若有疏漏和問題還請留言斧正和補充。
以下是本文所涉及到的知識點,break or continue ?
原理很簡單,就是根據 http 協議的規范和定義,完成請求消息體的封裝和消息體的解析,然后將二進制內容保存到文件。
我們都知道如果要上傳一個文件,需要把 form 標簽的enctype設置為multipart/form-data,同時method必須為post方法。
那么multipart/form-data表示什么呢?
multipart互聯網上的混合資源,就是資源由多種元素組成,form-data表示可以使用HTML Forms 和 POST 方法上傳文件,具體的定義可以參考RFC 7578。
multipart/form-data 結構
看下 http 請求的消息體
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次請求要上傳文件,其中boundary表示分隔符,如果要上傳多個表單項,就要使用boundary分割,每個表單項由———XXX開始,以———XXX結尾。
每一個表單項又由Content-Type和Content-Disposition組成。
Content-Disposition: form-data 為固定值,表示一個表單元素,name 表示表單元素的 名稱,回車換行后面就是name的值,如果是上傳文件就是文件的二進制內容。
Content-Type:表示當前的內容的 MIME 類型,是圖片還是文本還是二進制數據。
解析
客戶端發送請求到服務器后,服務器會收到請求的消息體,然后對消息體進行解析,解析出哪是普通表單哪些是附件。
可能大家馬上能想到通過正則或者字符串處理分割出內容,不過這樣是行不通的,二進制buffer轉化為string,對字符串進行截取后,其索引和字符串是不一致的,所以結果就不會正確,除非上傳的就是字符串。
不過一般情況下不需要自行解析,目前已經有很成熟的三方庫可以使用。
至于如何解析,這個也會占用很大篇幅,后面的文章在詳細說。
使用 form 表單上傳文件
在 ie時代,如果實現一個無刷新的文件上傳那可是費老勁了,大部分都是用 iframe 來實現局部刷新或者使用 flash 插件來搞定,在那個時代 ie 就是最好用的瀏覽器(別無選擇)。
DEMO
這種方式上傳文件,不需要 js ,而且沒有兼容問題,所有瀏覽器都支持,就是體驗很差,導致頁面刷新,頁面其他數據丟失。
HTML
<form method="post" action="http://localhost:8100" enctype="multipart/form-data">
選擇文件:
<input type="file" name="f1"/> input 必須設置 name 屬性,否則數據無法發送<br/>
<br/>
標題:<input type="text" name="title"/><br/><br/><br/>
<button type="submit" id="btn-0">上 傳</button>
</form>
復制代碼
服務端文件的保存基于現有的庫koa-body結合 koa2實現服務端文件的保存和數據的返回。
在項目開發中,文件上傳本身和業務無關,代碼基本上都可通用。
在這里我們使用koa-body庫來實現解析和文件的保存。
koa-body 會自動保存文件到系統臨時目錄下,也可以指定保存的文件路徑。
然后在后續中間件內得到已保存的文件的信息,再做二次處理。
NODE
/**
* 服務入口
*/
var http=require('http');
var koaStatic=require('koa-static');
var path=require('path');
var koaBody=require('koa-body');//文件保存庫
var fs=require('fs');
var Koa=require('koa2');
var app=new Koa();
var port=process.env.PORT || '8100';
var uploadHost=`http://localhost:${port}/uploads/`;
app.use(koaBody({
formidable: {
//設置文件的默認保存目錄,不設置則保存在系統臨時目錄下 os
uploadDir: path.resolve(__dirname, '../static/uploads')
},
multipart: true // 開啟文件上傳,默認是關閉
}));
//開啟靜態文件訪問
app.use(koaStatic(
path.resolve(__dirname, '../static')
));
//文件二次處理,修改名稱
app.use((ctx)=> {
var file=ctx.request.files.f1;//得道文件對象
var path=file.path;
var fname=file.name;//原文件名稱
var nextPath=path+fname;
if(file.size>0 && path){
//得到擴展名
var extArr=fname.split('.');
var ext=extArr[extArr.length-1];
var nextPath=path+'.'+ext;
//重命名文件
fs.renameSync(path, nextPath);
}
//以 json 形式輸出上傳文件地址
ctx.body=`{
"fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
}`;
});
/**
* http server
*/
var server=http.createServer(app.callback());
server.listen(port);
console.log('demo1 server start ...... ');
復制代碼
CODE
https://github.com/Bigerfe/fe-learn-code/
*請認真填寫需求信息,我們會在24小時內與您取得聯系。