nodejs
nodejs中没有DOM和BOM
console.log(document) console.log(window) |
代码运行报错如下:
C:\Users\Dell\Desktop\node\1.js:1 (function (exports, require, module, __filename, __dirname) { console.log(docume nt) ^ ReferenceError: document is not defined at Object.(C:\Users\Dell\Desktop\node\1.js:1:75) at Module._compile (module.js:652:30) at Object.Module._extensions..js (module.js:663:10) at Module.load (module.js:565:32) at tryModuleLoad (module.js:505:12) at Function.Module._load (module.js:497:3) at Function.Module.runMain (module.js:693:10) at startup (bootstrap_node.js:191:16) at bootstrap_node.js:612:3
以读取文件为例,来看看异步回调函数中的参数
读取一个不存在的文件 error为一个对象,data为undefined
var fs=require('fs'); fs.readFile('./2.html',function(error,data){ console.log(error); /* { Error: ENOENT: no such file or directory, open 'C:\Users\Dell\Desktop\node\2.html' errno: -4058, code: 'ENOENT', syscall: 'open', path: 'C:\\Users\\Dell\\Desktop\\node\\2.html' } */ console.log(data); //undefined if(error){ console.log(error); }else{ console.log(data); } }) |
读取一个存在的文件
var fs=require('fs'); fs.readFile('./2.html',function(error,data){ console.log(error); //null console.log(data.toString()); //2.html中的内容 if(error){ console.log(error); }else{ console.log(data); // 十六进制内容 } }) |
请求成功时,回调函数中的参数
data 数据 error null
请求失败时,回调函数中的参数
data undefined error 对象
综上,可以根据error来判断是否发生错误,操作是否成功。
”.toString()结果为空,null.toString()会报错
http服务器
var http=require('http') var server=http.createServer() server.on('request',function(request,response){ console.log(request.url+'已收到请求') //response.write可以使用多次,最后一定要用response.end来结束响应,否则客户端会一直等待 response.write('hello') response.end('nodejs') }) server.listen(3000,function(){ console.log('服务器启动成功,可以通过http://127.0.0.1:3000来访问') }) |
https://lvtao.net/content/book/node.js.htm
三种模块
具名的核心模块
用户自己编写的文件模块
require引入模块文件路径
同路径下,文件路径必须加./,直接require(‘文件名’)会报找不到文件,可以省略后缀名.js
在node中,没有全局作用于,只有模块作用域
import用法解释
import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js后缀可以省略。如果只是模块名,不带有路径,那么必须有配置文件,告诉 JavaScript 引擎该模块的位置。某些打包工具可以允许或要求使用扩展名。
默认导出,export 命名导出需要export 名字和import名字严格一致。而export default命令,为模块指定默认输出,在import 的时候可以随意命名名字。一个模块只能有一个默认输出,也就是说 export default 一个模块只能用一次。
node中exports的使用
模块文件
3.js
exports.ext='js'; exports.add=function(a,b){ return a+b; } |
导入模块的文件
2.js
var obj=require('./3.js'); console.log(obj); // { ext: 'js', add: [Function] } console.log(obj.ext); // js var result=obj.add(100,200); console.log(result); // 300 |
模块间的通信
exports默认是一个空对象,你可以在模块中自定义模块成员和属性.
node中module.exports的使用
通过module对象可以访问到当前模块的一些相关信息,但最多的用途是替换当前模块的导出对象。例如模块导出对象默认是一个普通对象,如果想改成一个函数的话,可以使用以下方式。
模块文件
module.exports=function add(a,b){ return a*b; } |
导入模块的文件
var addFun=require('./4.js') var result=addFun(100,250); console.log(result); // 25000 |
一个模块中的JS代码仅在模块第一次被使用时执行一次,并在执行过程中初始化模块的导出对象。之后,缓存起来的导出对象被重复利用。
ip地址用来定位计算机,端口号用来定位软件.所有需要联网的软件都需要一个端口号
获取发送请求的端口
request.socket.remotePort
var http=require('http') var server=http.createServer() server.on('request',function(request,response){ console.log(request.socket.remotePort) //获取用户访问端口 response.end('nodejs') }) server.listen(3000,function(){ console.log('服务器启动成功,可以通过http://127.0.0.1:3000来访问') }) |
响应中文乱码
var http=require('http'); var server=http.createServer(); server.on('request',function(request,response){ response.write('服务器发送来的响应') response.end() }) server.listen(5000,function(){ console.log('http创建成功,可以通过访问127.0.0.1:3000访问') }) |
默认响应以utf8编码方式返回给浏览器,但是浏览器无法识别这是utf8的内容,浏览器在不知道是什么编码的内容,会以当前操作系统的默认编码去解析内容,中文操作系统默认是gbk。
解决方法:
var http=require('http'); var server=http.createServer(); server.on('request',function(request,response){ response.setHeader('Content-type','text/plain;charset=utf-8'); // text/plain当做普通文本解析,text/html当做html内容解析 response.write('服务器发送来的响应') response.end() }) server.listen(5000,function(){ console.log('http创建成功,可以通过访问127.0.0.1:3000访问') }) |
根据不同的响应内容,设置不同的content-type
var http=require('http'); var server=http.createServer(); var fs=require('fs') server.on('request',function(request,response){ if(request.url==='/index' || request.url==='/'){ fs.readFile('./static/index.html',function(error,data){ if(error){ response.setHeader('content-type','text/plain;charset=utf-8'); response.end('请求发生错误'); }else{ response.setHeader('content-type','text/html;charset=utf-8'); response.end(data); } }) }else if(request.url==='/zs'){ fs.readFile('./static/zs.jpg',function(error,data){ if(error){ response.setHeader('content-type','text/plain;charset=utf-8'); response.end('请求发生错误'); }else{ response.setHeader('content-type','image/jpeg'); response.end(data); } }) } }) server.listen(5000,function(){ console.log('http创建成功,可以通过访问127.0.0.1:3000访问') }) |
注意:只有内容为字符文本内容数据时,才有必要设置编码,像图片之类的内容没有必要。
代码中是否用分号
当一行代码以 ( , [ , ` 开头的时候,则前面加上一个分号用以避免一些语法解析错误。
function say() { console.log('hello'); } say() //在这里加上分号可以解决报错问题 (function(){ console.log('hello') })() |
报错:
hello C:\Users\Dell\Desktop\node\1.js:5 (function(){ ^ TypeError: say(...) is not a function at Object.(C:\Users\Dell\Desktop\node\1.js:5:1) at Module._compile (module.js:652:30) at Object.Module._extensions..js (module.js:663:10) at Module.load (module.js:565:32) at tryModuleLoad (module.js:505:12) at Function.Module._load (module.js:497:3) at Function.Module.runMain (module.js:693:10) at startup (bootstrap_node.js:191:16) at bootstrap_node.js:612:3
服务器端渲染
模板文件template.html
<tbody id="tbody"> {{each data}} <tr><td data-value="1111"><a class="icon file" draggable="true" href="/E:/MUI%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B/MUI%E5%BE%AE%E4%BF%A1%E5%AE%9E%E6%88%98/01-HTML5%E6%B7%B7%E5%90%88%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E4%B8%8EMUI%E6%A1%86%E6%9E%B6.mp4"> {{$value}}</a></td><td class="detailsColumn" data-value="96543985">92.1 MB</td><td class="detailsColumn" data-value="1546563599">2019/1/4 上午8:59:59</td></tr> {{/each}} </tbody> |
nodejs读取某个文件的目录数据,并渲染页面
var http=require('http') var fs=require('fs') var server=http.createServer() var template=require('art-template') server.on('request',function(request,response){ //路径名称必须用正斜杠 fs.readdir('../node',function(error,data){ if(error){ return console.log(error) } var files='' console.log(JSON.stringify(data)) var html=template(__dirname + '/template.html',{data:data}) response.end(html); }) }) server.listen(3000,function(){ console.log('server is running'); }) |
静态资源
注意:在服务端中,文件中的路径就不要去写相对路径了。
因为这个时候所有的资源都是通过 url 标识来获取的
我的服务器开放了 /public/ 目录
所以这里的请求路径都写成:/public/xxx
/ 在这里就是 url 根路径的意思。
浏览器在真正发请求的时候会最终把 http://127.0.0.1:3000 拼上
不要再想文件路径了,把所有的路径都想象成 url 地址
执行
> url.parse('https://www.baidu.com/s?wd=melody&rsv_spt=1&rsv_iqid=0xec3cb13d0002 21a5&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3 =6&rsv_sug1=6&rsv_sug7=101') Url { protocol: 'https:', slashes: true, auth: null, host: 'www.baidu.com', port: null, hostname: 'www.baidu.com', hash: null, search: '?wd=melody&rsv_spt=1&rsv_iqid=0xec3cb13d000221a5&issp=1&f=8&rsv_bp=0&rsv_idx =2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=6&rsv_sug1=6&rsv_sug7=101', query: 'wd=melody&rsv_spt=1&rsv_iqid=0xec3cb13d000221a5&issp=1&f=8&rsv_bp=0&rsv_idx= 2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=6&rsv_sug1=6&rsv_sug7=101', pathname: '/s', path: '/s?wd=melody&rsv_spt=1&rsv_iqid=0xec3cb13d000221a5&issp=1&f=8&rsv_bp=0&rsv_i dx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=6&rsv_sug1=6&rsv_sug7=101', href: 'https://www.baidu.com/s?wd=melody&rsv_spt=1&rsv_iqid=0xec3cb13d000221a5&issp =1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=6&rsv_su g1=6&rsv_sug7=101' } |
执行
> url.parse('https://www.baidu.com/s?wd=melody&rsv_spt=1&rsv_iqid=0xec3cb13d000221a5&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=6&rsv_sug1=6&rsv_sug7=101',true) Url { protocol: 'https:', slashes: true, auth: null, host: 'www.baidu.com', port: null, hostname: 'www.baidu.com', hash: null, search: '?wd=melody&rsv_spt=1&rsv_iqid=0xec3cb13d000221a5&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=6&rsv_sug1=6&rsv_sug7=101', query: [Object: null prototype] { wd: 'melody', rsv_spt: '1', rsv_iqid: '0xec3cb13d000221a5', issp: '1', f: '8', rsv_bp: '0', rsv_idx: '2', ie: 'utf-8', tn: 'baiduhome_pg', rsv_enter: '1', rsv_sug3: '6', rsv_sug1: '6', rsv_sug7: '101' }, pathname: '/s', path: '/s?wd=melody&rsv_spt=1&rsv_iqid=0xec3cb13d000221a5&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=6&rsv_sug1=6&rsv_sug7=101', href: 'https://www.baidu.com/s?wd=melody&rsv_spt=1&rsv_iqid=0xec3cb13d000221a5&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=6&rsv_sug1=6&rsv_sug7=101' } |
node.js实现简易留言板代码
post.html发表留言页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="/public/css/bootstrap.css"> </head> <body> <div class="header container"> <div class="page-header"> <h1><a href="/">首页</a> <small>发表评论</small></h1> </div> </div> <div class="comments container"> <!-- 以前表单是如何提交的? 表单中需要提交的表单控件元素必须具有 name 属性 表单提交分为: 1. 默认的提交行为 2. 表单异步提交 action 就是表单提交的地址,说白了就是请求的 url 地址 method 请求方法 get post --> <form action="/postcomment" method="get"> <div class="form-group"> <label for="input_name">你的大名</label> <input type="text" class="form-control" required minlength="2" maxlength="10" id="input_name" name="name" placeholder="请写入你的姓名"> </div> <div class="form-group"> <label for="textarea_message">留言内容</label> <textarea class="form-control" name="content" id="textarea_message" cols="30" rows="10" required minlength="5" maxlength="20"></textarea> </div> <button type="submit" class="btn btn-default">发表</button> </form> </div> </body> </html> |
留言展示页面 index.html
<!DOCTYPE html> <!-- saved from url=(0027)http://192.168.150.76:3000/ --> <html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>留言本</title> <!-- 浏览器收到 HTML 响应内容之后,就要开始从上到下依次解析, 当在解析的过程中,如果发现: link script img iframe video audio 等带有 src 或者 href(link) 属性标签(具有外链的资源)的时候,浏览器会自动对这些资源发起新的请求。 --> <!-- 注意:在服务端中,文件中的路径就不要去写相对路径了。 因为这个时候所有的资源都是通过 url 标识来获取的 我的服务器开放了 /public/ 目录 所以这里的请求路径都写成:/public/xxx / 在这里就是 url 根路径的意思。 浏览器在真正发请求的时候会最终把 http://127.0.0.1:3000 拼上 不要再想文件路径了,把所有的路径都想象成 url 地址 --> <link rel="stylesheet" href="/public/css/bootstrap.css"> </head> <body> <div class="header container"> <div class="page-header"> <h1>Example page header <small>Subtext for header</small></h1> <a class="btn btn-success" href="/post">发表留言</a> </div> </div> <div class="comments container"> <ul class="list-group"> {{each $data}} <li class="list-group-item">{{$value.name}} 说:{{$value.content}} <span class="pull-right">2017-11-2 17:11:22</span></li> {{/each}} </ul> </div> </body> </html> |
main.js
var http = require('http') var fs = require('fs') var url = require('url') var template = require('art-template') var comments = [ { name: 'xiaoming', content: '今年找到女友了没?' }, { name: 'xiaogang', content: '前段时间找了个,但是人家要车要房!' }, { name: 'xiaoming', content: '然后?' }, { name: 'xiaogang', content: '然后就被甩了~' } ]; console.log(comments); http .createServer(function (request, response) { var path = url.parse(request.url, true) //获取一个url参数相关的对象 var pathName = path.pathname //获取url全路径,不包括问号以及问号之后的内容 if (pathName === '/') { //评论首页内容 fs.readFile('./index.html', function (error, data) { if (error) { return console.log('404 not found'); } var html = template(__dirname+'/index.html', comments) response.end(html); }) } else if (pathName === '/post') { //评论页面 fs.readFile('./post.html', function (error, data) { if (error) { return console.log(error); } response.end(data); }) } else if (pathName === '/postcomment') { //用户发表评论内容 var name = path.query.name var content = path.query.content comments.push({ name: name, content: content }); console.log('push后的数据' + comments); response.statusCode = 302 response.setHeader('location', '/') response.end() } else if (pathName.indexOf('/public/') === 0) { //静态资源 fs.readFile('./' + pathName, function (error, data) { if (error) { return console.log('404 not found'); } response.end(data); }) } else { //404处理 response.end('404'); } }).listen(3000) |
如何通过服务器让客户端重定向?
1.状态码设置为302临时重定向
statusCode
2.在响应头中通过location告诉客户端往哪儿重定向
setHeader
如果客户端发现收到服务器的响应的状态码是302,就会自动去响应头去找location
最后就可以看到客户端跳转
require 加载规则
优先从缓存加载
不可能有任何一个第三方包和核心模块的名字是一样的
require(‘模块标识符’)
路径形式的模块
以’./’,’../’开头的相对路径
以’/’开头,在这里表示的是当前文件模块所属磁盘根路径,另外还有带盘符的路径,不推荐使用.
第三方模块加载(以art-template为例)
require(‘art-template’)
node_modules/art-template
node_modules/art-template/package.json
根据main属性中,记录了该模块的入口文件,如果package.json文件不存在或者main指定的入口模块也没有,则node会自动找该目录下的index.js
如果以上任何一个条件都不成立,则会从上一个目录的node_modules查找,上级目录也找不到,则会一直往上找,直到磁盘根目录的node_modules,如果找不到则报错
./是否可以省略
文件操作中的相对路径./可以省略,require(‘模块标识符’)中的模块标识符如果是以路径标识,相对路径./不能省略.
express框架
npm install express -S
const express = require('express') const app = express() app.get('/', function (request,response) { response.send('hello word') }) app.get('/about', function (request,response) { response.send('about us') }) app.get('/love', function (request,response) { response.send('love u') }) //http://127.0.0.1:3000/static/zs.jpg 访问static目录下的zs.jpg文件 路径static下,url包含static //app.use('/static', express.static('./static')) //http://127.0.0.1:3000/zs.jpg 访问static目录下的zs.jpg文件 路径static下,url中不包含static app.use(express.static('static')) //http://127.0.0.1:3000/zs2.jpg 访问public目录下的zs2.jpg文件 路径public下,url不包含public app.use(express.static('public')) app.listen(3000, function () { console.log('服务器启动,可以通过127.0.0.1:3000访问') }) |
使用express-art-template
express-art-template安装
npm install --save art-template npm install --save express-art-template
在编写调试Node.js项目,修改代码后,需要频繁的手动close掉,然后再重新启动,非常繁琐。现在,我们可以使用nodemon这个工具,它的作用是监听代码文件的变动,当代码改变之后,自动重启。
nodemon安装
npm install nodemon -g
nodemon使用
使用nodemon app.js执行node命令,以后此文件有修改则自动保存文件
express重写留言板
const express = require('express') const app = express() var comments = [ { name: 'xiaoming', content: '今年找到女友了没?' }, { name: 'xiaogang', content: '前段时间找了个,但是人家要车要房!' }, { name: 'xiaoming', content: '然后?' }, { name: 'xiaogang', content: '然后就被甩了~' } ]; //静态资源存放路径 url可以省略public app.use(express.static('public')) app.engine('html', require('express-art-template')) app.get('/', function (req,res) { res.render('index.html', {comments}) }) app.get('/post-comment', function (req, res) { //提交评论数据 comments.push({name:req.query.name, content:req.query.content}) res.redirect('/'); }) app.get('/post', function (req, res) { res.render('post.html') }) app.listen(3000, function () { console.log('服务器启动成功') }) |
express利用body-parser解析表单post数据
安装
npm install body-parser -S
const express = require('express') const app = express() var bodyParser = require('body-parser'); var comments = [ { name: 'xiaoming', content: '今年找到女友了没?' }, { name: 'xiaogang', content: '前段时间找了个,但是人家要车要房!' }, { name: 'xiaoming', content: '然后?' }, { name: 'xiaogang', content: '然后就被甩了~' } ]; // 静态资源存放路径 url可以省略public app.use(express.static('public')) // 解析 application/json app.use(bodyParser.json()); // 解析 application/x-www-form-urlencoded app.use(bodyParser.urlencoded({ extended: true })); app.engine('html', require('express-art-template')) app.get('/', function (req,res) { res.render('index.html', {comments}) }) app.post('/post', function (req, res) { //提交评论数据 console.log(req.body) //{ name: '3432423', content: '345345345345' } comments.push({name:req.body.name, content:req.body.content}) res.redirect('/'); }) app.get('/post', function (req, res) { res.render('post.html') }) app.listen(3000, function () { console.log('服务器启动成功') }) |
建议不要用 cnpm 安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org |