(一)实例一:写一个简单的服务器
一、nodejs写服务器
1、下载github代码
2、开始操作:
(1)分析项目文件step0中的文件index.js,代码如下:
var http = require('http')//是nodejs的内置模块——http(服务器)
即nodejs通过require加载一个模块(一个对象,提供了一些方法能够实现所需要的功能),服务器的底层是由这个nodejs的http模块实现
(2)回到项目文件,用nodejs的内置模块创建一个server:
http.createServer(function(req , res){
})//内含一个回调函数
以上函数实质上内部是一个异步过程,内部可以创建一个服务器,以这个函数作为对应的参数去处理请求。
当浏览器去访问这个服务器的时候,该请求底层会被封装成一个对象。
一个对象:参数req(随意取名),即用户请求的信息都存在这个req对象中,通过获取req得到相关的信息数据(如用户IP、域名,以及一些浏览器的域名等等)
另一个对象:参数res,即需要返回给用户哪些东西
(3)最终在项目文件中创建一个有着基本设置的服务器
代码如下:
//index.js
var http = require('http')
var server = http.createServer(function(req, res){
console.log(req) //用户请求所附带的信息
res.write('hello world') //返回浏览器自带的一些信息
res.end()
})
server.listen(9000) //用listen启动这个静态服务器
(4)终端启动:
$ node index.js
此时终端进入一个空白状态(输入无用),即服务器处于一个启动状态,等待用户输入
(5)浏览器输入服务器地址:localhost:9000 (地址不一定一样,端口号自己弄)
出现如图:
同时,终端相应出现req这个对象所附带的用户请求的信息(随意截图)
注:事实上,console.log所执行的请求数据,除了可以是设定好的参数req,也可以是任意字符串,或者包含数据的json数据等等(不演示了)
至此,写了一个简单的服务器
延伸:解析一下响应体如何进入服务器——服务器处理请求——返回数据:
拿 res.write('hello world')举例:
res.write(即一个响应体)是把数据(即'helloworld')放到http的response响应体里(即响应内容里)
当我们代码请求后输入url发出网络请求,请求时浏览器自动添加响应头相关信息,请求发至服务器之后,则会开始执行以下代码:【这里就是开发者开发不同页面的个性创造所在】
var server = http.createServer(function(req, res){
console.log(req) //用户请求所附带的信息
res.write('hello world') //返回浏览器带的信息(即响应体,页面展现的内容)
res.end()
})
该服务器发了一个响应res(response),此时服务器后台出现响应头(一些浏览器默认参数),如图:
响应体对应代码中,则res所请求的内容,这里是'hello world':
总结,这是网站后台的一个基本逻辑
3、扩展:设置响应头
通过res.setHeader()设置响应头,如可添加:
res.setHeader("Content-Type","text/plain; charset=utf-8")
//text/plain 表示返回内容用字符串(明文)去呈现或者当成html渲染,如text/html
//charset=gbk 表示返回的内容用gbk解码,也可设置为charset=utf-8解码
即项目文件代码为:
//index.js
var http = require('http')
var server = http.createServer(function(req, res){
console.log('jiengu')//服务器响应的内容
res.setHeader("Content-Type","text/plain; charset=utf-8")
res.write('你好世界')//响应体:页面展现的内容
res.end()
})
server.listen(9000)
重启终端:
$ node index.js
服务器后台响应头设置相应参数后,出现如图:
注意: 如出现乱码文件,实质可以在服务器的响应头层面去设置编码方式。如果返回的是一个html则可以从meta里去设置
延伸:ajax的请求头 VS nodejs的响应头
miya Wang:#hello,JS:12-01技术方案:Ajax 使用和原理
- ajax请求头:即服务器发送、返回时带的一些资源数据,如将url包含的一些各类数据作为请求资源,做一些加载、拼接等,然后返回结果数据。
- nodejs的响应头:服务器对所请求的东西后台参数的一些响应,如设置页面展示效果的展示
4、加一个定时器观察服务器的响应
项目文件代码如下:
//项目文件:(新)index.js
var http = require('http')
var server = http.createServer(function(request, response){
setTimeout(function(){
response.setHeader('Content-Type','text/html; charset=utf-8')
//响应头:论及权限高,charset=utf-8作为请求http(浏览器)级别的请求,去解码
//发一个请求去响应:头、身体内容,根据头解释身体内容(一堆字符串)
response.writeHead(404, 'Not Found')
response.write('<html><head><meta charset="gbk" /></head>')
response.write('<body>')
response.write('<h1>你好</h1>')
response.write('</body>')
response.write('</html>')
response.end()
},2000);
})
console.log('open http://localhost:8080')
server.listen(8080)
重新启动终端:
$ node index.js
检查——控制台
延伸:针对http对应的状态码作用
先看到几个效果:
当Status Code:200时,如图:
当Status Code:400时,如图:
页面打开了(页面出现:你好)请求是成功的,但是打开控制台显示请求为红色,且console出现报错:404(Not found)。一旦浏览器收到状态码为404,它则认为文件请求失败,但实际上它也是收到请求并返回数据的。
总结:所请求的状态码通过response.writeHead()写出,完全由你来决定其页面呈现的状态
(二)实例二:实现一个静态服务器
准备好打包好的项目文件夹(包含html(css样式/js交互/图片))——网站放置在远程服务器上——通过执行服务器的相关js文件(执行node
server.js)——运行服务器
那么,这个运行服务器的js文件到底是怎么实现访问页面?
分析项目文件step1中的文件关键js文件:server.js,代码如下:
//server.js
var http = require('http') //前面说了,创建http服务器的底层内置模块
var path = require('path') //该模块可以处理不同系统下的url(不同系统路径写法不一)
var fs = require('fs') //该模块读、写文件
var url = require('url') //该模块自动解析url,读取信息,如控制台求location
function staticRoot(staticPath, req, res){
console.log(staticPath)
var pathObj = url.parse(req.url, true)
console.log(pathObj)
if(pathObj.pathname === '/'){
pathObj.pathname += 'index.html'
}
var filePath = path.join(staticPath, pathObj.pathname)
// var fileContent = fs.readFileSync(filePath,'binary')
// res.write(fileContent, 'binary')
// res.end()
fs.readFile(filePath, 'binary', function(err, fileContent){
if(err){
console.log('404')
res.writeHead(404, 'not found')
res.end('<h1>404 Not Found</h1>')
}else{
console.log('ok')
res.writeHead(200, 'OK')
res.write(fileContent, 'binary')
res.end()
}
})
}
console.log(path.join(__dirname, 'static'))
var server = http.createServer(function(req, res){
staticRoot(path.join(__dirname, 'static'), req, res)
})
server.listen(8080)
console.log('visit http://localhost:8080' )
当用户访问localhost:8080/index.html,如何让用户看到项目文件的内容呢?
实现的关键,分解来看:
var http = require('http')
var path = require('path')
var fs = require('fs')
var url = require('url')
var server = http.createServer(function(req, res){
staticRoot(path.join(__dirname, 'static'), req, res)
})
server.listen(8080)
console.log('visit http://localhost:8080' )
通过 http.creatServer创建一个server,listen去启动一个服务器,监听8080端口,请求到来之后,进入server这个函数里,处理这个请求
写一个函数staticRoot()作为静态文件路径,将路径名、req、res都传递进去,如:
staticRoot(path.join(__dirname, 'static'), req, res)
__dirname 为nodejs的内置变量,代表当前的文件server.js 再加上【static】,那么,path.join(__dirname, 'static') 则会生成一个 绝对路径
然后通过下面代码运行测试:
function staticRoot(staticPath, req, res){
console.log(staticPath)
}
控制台随即得到项目文件的相关文件信息,通过绝对路径能读取文件
获取路径之后进行操作,
需要通过用户的url,给用户返回一些特定内容,发出请求得到返回的是console.log(req.url),req.url所返回的均是项目文件中的相关文件,即请求的均是这些文件index.html、a.css、logo.png,并得到,得到之后进行解析,如何解析?代码如下:
var pathObj = url.parse(req.url, true)
console.log(pathObj)
实现一个默认页面:设置一个默认路径:localhost:8080/index.html ,如何实现?代码如下:
if(pathObj.pathname === '/'){
pathObj.pathname += 'index.html'
}
发现原来可以这样设置一个默认路径的页面,也是很兴奋哦~:
通过一个parseName 去得到一个完整路径,即静态目录路径则进入打包项目文件夹里,那么加上 pathObj.pathname 就得到该项目文件所请求的绝对路径地址 filePath,代码如下:
var filePath = path.join(staticPath, pathObj.pathname)
如何读取文件?代码如下
第1种:直接法
var fileContent = fs.readFileSync(filePath,'binary')
res.write(fileContent, 'binary')
res.end()
第2种:异步(也可作为当做制作404的页面状态)
fs.readFile(filePath, 'binary', function(err, fileContent){
if(err){
console.log('404')
res.writeHead(404, 'not found')
res.end('<h1>404 Not Found</h1>')
}else{
console.log('ok')
res.writeHead(200, 'OK')
res.write(fileContent, 'binary')
res.end()
}
})
?处理关于乱码的事情
(三)实例三:实现功能更复杂的静态服务器(使用nodejs服务器理由解析)
如url可获取任何数据,mock数据与前端交互
分析项目文件step2中的文件server-simple.js,代码如下:
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': //请求对应天气
var ret
if(pathObj.query.city == 'beijing'){
ret = {
city: 'beijing',
weather: '晴天'
}
}else{
ret = {
city: pathObj.query.city,
weather: '不知道'
}
}
res.end(JSON.stringify(ret))
break;
case '/user/123': //对应的路由
res.end( fs.readFileSync(__dirname + '/static/user.tpl' ))
break;
default:
res.end( fs.readFileSync(__dirname + '/static' + pathObj.pathname) )
}
}).listen(8080)
先分解简单代码:
var http = require('http')
var fs = require('fs')
//根据函数req.url进行语句操作,假设req.url是请求getWeather,
//res.end()括号内则是请求后所要获取的结果。
http.createServer(function(req, res){
switch (req.url){
case '/getWeather':
res.end(JSON.stringify({a:1,b:2}))
break;
case '/user/123':
res.end( fs.readFileSync(__dirname + '/static/user'))
break;
default:
res.end( fs.readFileSync(__dirname + '/static'+req.url))
}
}).listen(8080)
总结: 创建模块:http+fs模块——创建一个server——该server函数返回一个操作对象——该操作对象调用并启动端口为8080的服务器。当任何请求到来,只要以localhost:8080为前缀的url就会到达该服务器
终端启动:
$ node server-simple.js
刷新页面处理js文件中函数对象的请求,即
http.createServer(function(req, res){
switch (req.url){
case '/getWeather':
res.end(JSON.stringify({a:1,b:2}))
break;
case '/user/123':
res.end( fs.readFileSync(__dirname + '/static/user'))
break;
default: //表示用户希望请求的是一个静态文件,直接从static文件夹中读取文件req.url
res.end( fs.readFileSync(__dirname + '/static'+req.url))
}
}).listen(8080)
当我们访问static下的html、css、图片或者直接调取请求模块,都能获取相应的内容
一个复杂网站,具有静态功能,提供静态文件;可以处理动态路由;可以mock数据,通过以下代码启示:
var http = require('http')
http.createServer(function(req, res){
switch (req.url){
case '/getWeather':
res.end(JSON.stringify({a:1,b:2}))
break;
}
}).listen(8080)
可以写一个ajax:
//b.js
var xhr = new XMLHttpRequest()
xhr.open('GET', '/getWeather?city=hangzhou', true)
xhr.send()
xhr.onload = function(){
console.log(JSON.parse(xhr.responseText))
}
待续...
看nodejs这一节最后的时候,不知道是有点困逻辑无法梳理,还有一点复杂服务器的实现暂时看得不是很懂😂。并且对于nodejs的一些理论基础知识也是相对空白,看了阿里出品的《七天学会NodeJS》才发现原来老师是将理论融进这短短的几节课,然后就理解了很多理论的知识。