var http = require('http') // http是nodejs裏面的一個模塊,這個對象可以提供實現底層的方法。咱們經過require去加載這個模塊 var server = http.createServer(function(req, res){ // 函數內部建立一個服務器,建立好以後,經過瀏覽器訪問這個服務器的時候,會把請求封裝成一個對象 // 這個對象就是這個回調函數的第一個參數req。用戶請求的信息都在這個對象內,能夠獲取用戶的信息,如ip,請求信息等。 // 第二個參數res是服務器返回給用戶的信息 console.log('jiengu') res.setHeader("Content-Type","text/html; charset=utf-8") //設置響應頭的content-type內容,text/html是把響應體當成html解析, res.write('<h1> 飢人谷</h1>') //在res寫入服務器返回給瀏覽器的內容 res.end() }) server.listen(9000) // 經過listen方法來啓動他,服務器監聽9000端口
打開gitbash,切換到js文件當前的文件夾,而後輸入node index.js(index.js是個人js文件名,反正大家取什麼名就輸入啥名)css
打開瀏覽器,輸入http://127.0.0.1:9000/,或者http://localhost:9000/
注意哈9000是代碼裏面寫的9000端口,若是下次改爲了8080等其餘的端口,那就改爲對應的端口就好html
響應頭查看路徑:network-name-headers前端
響應體:
響應體是response的數據,有點相似於打開網頁的查看源代碼node
每次修改了js文件的內容以後,要斷掉git的服務器,從新鏈接。否則即便刷新網頁沒有辦法顯示修改的內容git
4.1response.setHeader
格式:response.setHeader(name, value)
爲一個隱式的響應頭設置值。 若是該響應頭已存在,則值會被覆蓋。 若是要發送多個名稱相同的響應頭,則使用字符串數組。 非字符串的值會保留原樣,因此 response.getHeader() 會返回非字符串的值。 非字符串的值在網絡傳輸時會轉換爲字符串。
舉例:github
response.setHeader('Content-Type', 'text/plain'); //當成字符串解析
response.setHeader('Content-Type','text/html; charset=utf-8')//當成html解析,若是是css就設置爲text/css
執行結果ajax
setHeader引伸的連接,是nodejs中文網的規範json
4.2 response.writeHead()
writeHead文檔規範
格式:response.writeHead(statusCode, statusMessage)
參數1 statusCode(狀態碼)是一個三位數的 HTTP 狀態碼,如 404。
參數2是 statusMessage 是可選的狀態描述,是一個string。
參數3 headers 是響應頭,是個對象。其實咱們能夠理解爲這個對象放的是response headers所有內容。咱們設置的writehead的內容處理status碼是放在general,其餘的內容都是封裝成一個對象放在響應頭內容response headers。api
response.writeHead(404, 'Not Found')
res.writeHead(200,'hhh', { 'Content-Type':'text/plain;charset=utf-8','X-Foo':'bar2222'});
4.3二者的不一樣數組
4.4遇到的坑
坑1:res.setHeader("Content-Type","text/html; charset=gbk")
纔是對的,charset=gbk必須放在Content-Type內部,展現的時候也是在一塊兒。(我猜測charset應該是Content-Type的一部分)
若是分開寫成下面的格式,不會報錯,但charset就變成了響應頭的單獨子項展現,並且charset=utf-8不會生效(下圖utf-8沒有生效就按照gbk去解碼,就出現了亂碼)。
res.setHeader('Content-Type', 'text/html'); res.setHeader("charset","utf-8")
因此必定注意寫法
坑2:writeHead只能寫一次,全部響應頭要設置的內容都要按照對象的格式,放在參數三headers裏面。如下縮寫是正確的,要記住啊
res.writeHead(200,'hhh', { 'Content-Type':'text/plain;charset=utf-8','X-Foo':'bar2222'});
坑3:response.setHeader() 設置的響應頭會與 response.writeHead() 設置的響應頭合併,可是若是設置的內容重複,以response.writeHead() 的優先爲準。
var server = http.createServer(function(req, res){ res.setHeader("Content-Type","text/html; charset=utf-8") res.setHeader('X-Foo', 'bar'); res.writeHead(200,'hhh', { 'Content-Type':'text/plain;charset=utf-8','X-Foo':'bar2222'}); res.write('<h1> 飢人谷2</h1>') res.end() }) server.listen(9000)
執行結果是:很明顯的看到setHeader和writeHead重複設置的內容,都是以writeHead爲準的
4.5設置status的異常
res.writeHead(404,'hhh');
當我設置status爲404,發現即便是請求成功回送以後,也會出現紅色。這是由於你們約定404就是一個錯誤的狀態,因此status的值要按照約定來設置
搭建一個有圖片,css,js的資源的服務器,github代碼連接
輸出內容
var http = require('http') var path = require('path') // path模塊處理url,不一樣系統(mac/lincx/window)下對url的寫法可能不一致的。(一個寫成c:/project/code/a.png // 另一個可能寫成/user/local/project/a.png)。path模塊會對這種狀況自動處理url類型 var fs = require('fs') // fs模塊用來讀取文件數據,也能夠往文件裏面寫數據。 var url = require('url') // url模塊能夠自動解析url,獲得一個對象,能夠得到對應的信息。 function staticRoot(staticPath, req, res){ console.log(staticPath) //輸出static文件的絕對路徑,/user/documents/code/node-server/step1/static console.log(req.url) //請求的url地址,第一次調用html時,爲/index.html,第二次調用css時,就是css/a.css var pathObj = url.parse(req.url, true) // 解析url,獲得url對象(包含protocal/hostname/port/pathname/query等等),即pathobj對象就是url的對象。本次要用的是pathname console.log(pathObj) if(pathObj.pathname === '/'){ pathObj.pathname += 'index.html' } //若是pathname沒有輸入(瀏覽器輸入的值只是localhost:8080,沒有後綴的話),服務器默認選擇去讀取和發送index.html文件 var filePath = path.join(staticPath, pathObj.pathname) // staticPath=static文件夾的絕對路徑, pathObj.pathname=調用文件的後綴地址。 // 兩個加起來獲得filePath(用戶輸入的url想要訪問文件的絕對路徑),舉例本文是/user/documents/code/node-server/step1/static/index.html // var fileContent = fs.readFileSync(filePath,'binary') // res.write(fileContent, 'binary') // // 採用同步的方式讀取filePath的文檔,把讀取的數據寫入res對象內 // res.end() fs.readFile(filePath, 'binary', function(err, fileContent){ // 異步的方式來讀取filePath的文檔。binary指以二進制的方式來讀取數據,由於服務器不只僅要讀取普通的數據,須要兼容圖片和文件等數據。 if(err){ console.log('404') res.writeHead(404, 'not found') res.end('<h1>404 Not Found</h1>') // 在頁面展現404 Not Found。在res.end('數據')等於執行res.write('數據')加上res.end() }else{ console.log('ok') res.writeHead(200, 'OK') res.write(fileContent, 'binary') // 經過二進制的方式發送數據 res.end() } }) } console.log(path.join(__dirname, 'static')) // 在瀏覽器輸入localhost:8080/index.html地址,瀏覽器向服務器發起請求。 // 服務器收到請求後,執行相關函數,解析req對象信息,獲得了index.html的地址。 // 服務器根據解析的地址在本地static文件夾下找到對應的index.html文件,讀取html裏面數據,並把數據放在res內,當成字符串發給服務器。 var server = http.createServer(function(req, res){ staticRoot(path.join(__dirname, 'static'), req, res) //寫一個staticRoot函數,來處理請求。 /* 參數1:把哪一個路徑當成靜態文件路徑,傳遞路徑名。__dirname是nodejs裏面的一個變量,表明當前的server.js執行的這個文件。 path.join(__dirname, 'static')可使用一個或多個字符串值參數,該參數返回將這些字符串值參數結合而成的路徑。 var joinPath = path.join(__dirname, 'a', 'b', 'c'); console.log(joinPath); // D:\nodePro\fileTest\a\b\c, __dirname對應的step1文件夾的路徑,加上static文件夾得路徑,就等於static的絕對路徑。、 這樣的好處是每次絕對路徑發生變化的時候,不用從新去修改絕對路徑。*/ }) server.listen(8080) //建立一個服務器,監聽8080端口 console.log('visit http://localhost:8080' )
3.1 path node.js文檔中的標準解釋
path 模塊用於處理文件與目錄的路徑。不一樣系統(mac/lincx/window)下對url的寫法可能不一致的。(一個寫成c:/project/code/a.png
// 另一個可能寫成/user/local/project/a.png)。path模塊會對這種狀況自動處理url類型
3.2 path.join([...paths])
參數...paths <string> :路徑片斷的序列,返回: <string>
使用平臺特定的分隔符把全部 path 片斷鏈接到一塊兒,並規範化生成的路徑
path.join('C:\Users\jz\documents\code\node-server\step1' , 'static') //C:\Users\jz\documents\code\node-server\step1\static
3.3 fs 文件系統node.js文檔中的標準解釋
fs 模塊用於以一種相似標準 POSIX 函數的方式與文件系統進行交互。
全部的文件系統操做都有同步和異步兩種形式。
異步形式的最後一個參數是完成時的回調函數。 傳給回調函數的參數取決於具體方法,但第一個參數會保留給異常。 若是操做成功完成,則第一個參數會是 null 或 undefined。
3.4 fs.readFile(path[, options], callback)異步地讀取文件的內容
path 文件名或文件路徑
options 若是 options 是一個字符串,則指定字符編碼,默認爲 null
callback 是一個回調函數,有兩個參數 (err, data),其中 data 是要讀取文件的內容
fs.readFile(filePath, 'binary', function(err, fileContent){ // 異步的方式來讀取filePath的文檔。binary指以二進制的方式來讀取數據,由於服務器不只僅要讀取普通的數據,須要兼容圖片和文件等數據。 if(err){ console.log('404') res.writeHead(404, 'not found') res.end('<h1>404 Not Found</h1>') // 在頁面展現404 Not Found。在res.end('數據')等於執行res.write('數據')加上res.end() }else{ console.log('ok') res.writeHead(200, 'OK') res.write(fileContent, 'binary') // 經過二進制的方式發送數據 res.end() } })
3.5 fs.readFileSync(path[, options])
同步的讀取文件內容,兩個參數和異步的同樣的用法
// var fileContent = fs.readFileSync(filePath,'binary') // res.write(fileContent, 'binary') // // 採用同步的方式讀取filePath的文檔,把讀取的數據寫入res對象內 // res.end()
3.6 url模塊node.js文檔中的標準解釋
url 模塊提供了一些實用函數,用於 URL 處理與解析。 URL 字符串能夠被解析爲一個 URL 對象,其屬性對應於字符串的各組成部分。
3.7url.parse(urlString[, parseQueryString[, slashesDenoteHost]])
url.parse() 方法會解析一個 URL 字符串並返回一個 URL 對象。
urlString <string>
要解析的 URL 字符串。
parseQueryString <boolean>
若是爲 true,則 query 屬性總會經過 querystring 模塊的 parse() 方法生成一個對象。 若是爲 false,則返回的 URL 對象上的 query 屬性會是一個未解析、未解碼的字符串。 默認爲 false。
slashesDenoteHost <boolean>
若是爲 true,則 // 以後至下一個 / 以前的字符串會被解析做爲 host。 例如,//foo/bar 會被解析爲 {host: 'foo', pathname: '/bar'} 而不是 {pathname: '//foo/bar'}。 默認爲 false。
舉個例子
var pathObj = url.parse(req.url, true)// 解析req.url,獲得url對象pathobj
3.8__dirname
當前模塊的文件夾名稱。等同於 __filename 的 path.dirname() 的值
__filename 當前模塊的文件名稱---解析後的絕對路徑
例如:
在 /Users/mjr 目錄下執行 node example.js
console.log(__filename); // Prints: /Users/mjr/example.js console.log(__dirname); // Prints: /Users/mjr
有一個問題,爲何咱們要用req.url解析成url對象pathobj,再經過staticPath文件地址和pathobj.pastname結合成filepath,爲啥咱們不直接把req.url和staticPath結合在一塊兒生成filepath呢?這樣還少了一步呢
答案:若是requrl是常規的index.html或者css.css這種,兩種方式都不會報錯。可是若是url比較複雜,像是index.html?query=111#111這種,直接把req.url和staticPath結合在一塊兒是會報錯的,因此須要轉成url對象再把pashname挑出來。
實現更復雜的服務器,url不只僅是定位一個靜態文件,能夠mock任何數據和前端交互。
根據瀏覽器請求的不一樣路由,致使服務器執行不一樣的操做。
能夠查看GitHub上面的代碼,我這裏截圖說明
html
css
js,實現ajax的代碼
user.tpl
最重要的server-simple.js服務器代碼
本次演示的url是localhost:8080/user/123,localhost:8080以後的內容是路由。全部請求到8080這個服務器內,根據不一樣的路由給瀏覽器發送不一樣的數據
var http = require('http') var fs = require('fs') var url = require('url') http.createServer(function(req, res){ var pathObj = url.parse(req.url, true) console.log(pathObj) switch (pathObj.pathname){ case '/getWeather': //根據req.url來執行不一樣的函數 var ret if(pathObj.query.city == 'beijing'){ ret = { city: 'beijing', weather: '晴天' } }else{ ret = { city: pathObj.query.city, weather: '不知道' } } res.setHeader('content-Type','text/plain;charset=utf-8') res.end(JSON.stringify(ret)) //給瀏覽器輸入是一個json格式的對象,根據JSON.stringify轉換成字符串 break; case '/user/123': res.end( fs.readFileSync(__dirname + '/static/user.tpl' )) //若是路由是/user/123,讀取user.tpl的內容,並返回給瀏覽器 break; default: res.end( fs.readFileSync(__dirname + '/static' + pathObj.pathname) ) } }).listen(8080)
index.html
/getWeather
/user/123