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