typora-root-url: mynodeIMG
nodejs原生基础
知识点补充
node是什么
- node是一个执行环境
- node中的JavaScript
- node没有BOM
- 没有DOM
- 含有基本ECMA语法
- 含有服务器级别的API
静态与动态
- 静态 : 直接从服务器返回的数据, 没有和服务器交互
控制命令行
打开方法
- window + R 输入cmd
- 打开指定文件夹 按住shift + 鼠标右键 ==> 打开控制命令行
- 打开指定文件夹 在URL输入框内输入cmd
常用命令行
node -v // 查看当前nodejs版本
dir // 查看当前目录的所有文件夹
cd // 进去当前的某文件夹
cd.. //返回上级目录
cls // 清屏
exit // 离开
网站图标 ico
- 加载html页面默认会自动请求ico图标
- 生成 ico图标 :比特虫 (http://www.bitbug.net/)
- 将图标保存到静态资源根文件夹
HTTP协议
HTTP协议指的是服务器与浏览器之间通信要遵循一定的规则 :
- 浏览器请求服务器会向服务器发送请求报文,请求报文包括请求头和请求体
- 请求头包括 : 请求的URL, 请求的方式(get,post)
- 请求体
- 服务器和浏览器通信会向浏览器发送响应报文,包括响应头和响应体
- 响应头 : 状态码, 请求的数据类型
- 请求的内容
状态码
- 下面是常见的HTTP状态码:
- 200 - 请求成功
- 301 - 资源(网页等)被永久转移到其它URL
- 404 - 请求的资源(网页等)不存在
- 500 - 内部服务器错误
- HTTP状态码分类
状态码 | 说明 |
---|---|
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
跨域
-
跨域指的是在不同源的情况下ajax异步请求返回的数据,浏览器会进行拦截,不会执行回调函数.从而提示报错.
同源 : 相同的http或者https协议 / 相同的IP地址 / 相同的端口号
-
解决办法 :
-
response.setHeader('Access-Control-Allow-Origin','*');
在服务端返回请求头 -
使用第三方模块 : cors (一个专门处理跨域的第三方包)
const cors = require('cors'); //注册 允许跨域请求的 中间件 serverApp.use(cors())
-
jsonp
- 浏览器只是阻止ajax异步对象请求的跨域,并不会阻止script标签跨域请求的内容,因此,可以利用jsonp来请求数据
-
客户端 :
// 1. 提前准备一个自定义函数,作为接收函数的内容
funtion makeLove(data){alert(data)}
// 2. 点击按钮之后,动态创建一个script标签,标签的url为跨域请求服务器的URL,并且将自定义的函数名字绑定在URL上
$('btn').click(function(){
$('father').append('<secipt src="http://127.0.0.1:3000/add?funcName=showLove"></script>')
})
服务端 :
1. 当获取到客户端传递过来的数据后,用req.query 解析URL的函数名字
2. res.send( 传递过来的函数名字(传递的参数) )
// jQuery的jsonp封装
$.ajax({
url : url,
datatype : 'jsonp',
jsonp : 'funcName', // 指定的参数名称
jsonpCallback : 'showLove', // 指定的回调函数
})
端口号的理解
- 一句话 : ip定位计算机,端口号定位应用程序
- 每个电脑都有对应的IP地址,但是不同软件都需要和不同的服务器传输数据,所以为了不同软件之间数据互不影响,则需要对不同软件的通信取不同的端口 号.
- 取值范围是 0 - 65536 (3000,5000,8080等不常用,可以提供给自己使用)
- 可以同时开启多个服务器,只需要让端口号不一致就可以了
模块化(exports 和 module.exports的区别)
- Node中没有全局作用的概念,通过require来执行多个脚本文件
- 作用: 不能功能对应不同的模块,需要用啥,调用啥. 每个模块都有不同的API. 模块化互不影响,不会有污染问题,模块完全封闭,外部与内部互相不能访问. 因此需要通过exports来暴露对象
- 分类
- 核心模块 : fs(文件操作) http(服务器操作) os(机器信息) path(路径操作)
- 第三方模块 : 通过npm install *** --save
- 默认先找到node_modules/模块名
- 再找到package.json文件
- json中找到main属性, 属性通常为index.js : 入口模块
- 自定义模块 : (通过exports或者 module.exports来暴露,通过require来导入)
- 自定义模块引入必须要加 ./ 就算是当前目录 !!! / 表示的是当前磁盘的根目录
- 可以省略后缀名 .js
exports 和 module.exports的区别
-
实际上 exports = module.exports
-
用法区别:
-
exports.name = name; ======> exports只能通过点语来暴露出去
-
mudule.exports.name = name || mudule.exports = name =====> module.exports可以通过两种方法来暴露(点语法 或者 直接暴露)
-
通过点语法暴露的话只能通过点语法来调用 : let addlists = require(’./addlists’)
let addlists = require('./addlists') console.log(addlists.name)
-
通过 module.exports 可以直接获取
let addlists = require('./addlists') console.log(addlists)
-
-
区别的原理
-
了解堆栈的区别
let num1 = 10; let num2 = num1; num2++; console.log(num1); // 10 console.log(num2); // 11 // 总结: 在普通变量之间,通过直接开辟新的空间并复制相等的值,复制之后两个变量之间就没有关系了, //各自之间互不影响 //--------------------------------------------------------- let obj1 = {} let obj2 = obj1 obj2.name = '龚利明'; console.log(obj1); // {name : '龚利明'} console.log(obj2); // {name : '龚利明'} //总结 : 在对象之间,开辟新的空间,存储的是指向同一地方的地址. 当任一值的改变,两个变量的值都会改变. 此时如果让obj2指向新的对象: 如果让 obj2 = {} //name此时 obj1 和obj2是没有关联了的 此时exports 和 mudule.exports就是上述的对象 exports = module.exports 当exports = {} 新的对象的时候, exports和 module.exports就没有关联了,返回的肯定是module.exports,当中exports=XX时, module.exports返回的就是underfine 所以!!!! : exports不能直接暴露模块. 只能通过点语法.
-
npm命令行使用
简单介绍
- npm 是nodejs自带的. 只要安装了nodejs,默认就有npm
- npm是国外的一个服务器,里边有很多很多第三方的包(vue jQuery bootstrap等),需要用什么模块自己去调用就好
用法
npm -v //查看当前npm的版本
npm install npm --global // 升级当前npm global表示全局
//----------------------------------------------------------------
npm init //项目初始化
npm init -y // 项目初始化快捷键
npm install // 安装已经初始化的项目依赖包
npm install *** *** *** --save //安装需要的 *** 依赖包,并把依赖包的名字记录在 package
// 可以同时按照多个
npm uninstall *** --save //删除 *** 依赖包, 并且把记录从package中删除
cnpm
通过npm,但是从淘宝镜像下载(其实只是为了下载的速度),淘宝每十分钟和npm更新一次
安装方法
- npm config set registry https:// registry.npm.taobao.org
- 检查: npm config list
package.json 文件信息
name - 包名(项目名/模块名) - 必写
version - 包的版本号 - 必写
description - 描述
homepage - 官网地址
author - 作者,最好是 npmjs.org 的账户名(邮箱)
contributors - 包的其他贡献者
dependencies / devDependencies - 生产/开发环境依赖包列表
repository - 包代码的Repo信息,包括type和URL,type可以是git或svn,URL则是包的Repo地址。
main - main 字段指定了程序的主入口文件,require('moduleName') 就会加载这个文件
这个字段的默认值是模块根目录下面的 index.js。
keywords - 关键字
package-lock.json和package.json 的区别
- package.json只保存了当前的包和其依赖的模块,package-lock.json保存了这些模块的信息
- package-lock.json能加速包的下载速度
nodemon模块
- 作用 : 不用每次写了js代码重新 node app.js了
- 安装好后 : nodemon app.js就可以了
npm i nodemon -g
fs模块
读文件 readFile
- 传输成功的时候 err为null
let fs = require('fs');
fs.readFile(URL,(err, data)=>{
if(!err){
console.log(data.toString()) //如果不转成String 则显示的是 buffer的16进制的文件
//如果不读取 那就不要转啦!!!!
}
} )
读取文件目录 readdir
let fs = require('fs');
fs.readdir(URL,(err, data)=>{
if(!err){
console.log(data)
}
} )
写入 writeFile
let fs = require('fs');
fs.writerFile(URL,data,(err)=>{
if(!err){
console.log(err)
})
最简单服务器搭建
let http = require('http'); //导入 http\模块
let server = http.createServer((req, res)=>{ // 创建服务器
// req.url 默认是获取到端口号后面的内容
if(req.url == '/'){
res.writeHead(200,{'Content-Type':'text/html;charset=UTF-8'}); //charset是用的 = 号
res.write('hello');
res.end('world!');
}
else if(req.url == '/css/index.css'){
fs.readFile('./css/index.css',(err,data)=>{
if(!err){
res.writeHead(200,{'Content-Type':'text/css'});
res.end(data)
}
})
}
else{
res.end('访问出错了!!!')
}
})
server.listen(3000,'127.0.0.1'); //监听端口号和设置服务器的ip地址并启动服务器
-
注意点 :
- 端口号默认为80, 当修改成3000的时候,访问服务器必须加上端口号,80的时候可以不用
- req.url 默认是获取到端口号后面的内容
- res.end返回的必须是字符串或者二进制数据(布尔,数字,变量啥的都不行!)
-
Content-Type
- text/plain 普通文本
- text/html html文件
- text/css css文件
- 注意 : 我们的浏览器默认是gbk编码模式,请求头中需要添加文件格式为UTF-8 html文件默认就有meta标签来声明编码格式,因此不需要再设置charset=‘UTF-8’
总结 :
1. 其实在实际中,服务器传递过来htm文件的数据,浏览器会自动解析成html文件,(智能识别)
2. 在html文件中, 通过标签上的src或者href获取到的数据,因为是在标签中请求的嘛,所以数据也是能够自动解析的
url模块
为什么要用url模块
http://127.0.0.1:3000/nihao?name='naaa'
- 上边最简单的服务器中 : 直接通过 res.url返回的是 :
/nihao?name=%27naaa%27
当我们只需要/nihao时,或者只需要传递过来的数据就很尴尬了. 还要自己对URL进行字符串操作,特别的麻烦 - 用了url模块,能够把url里边需要各个部分都提取出来
使用方法
let http = require('http');
let url = require('url');
let server = http.createServe((req, res)=>{
let my_url = url.parse(req.url); // 用url模块 初始化url
//打印 my_yrl
console.log(my_url)
})
server.listen(3000,'127.0.0.1')
//------------------------------------
//输入的URL为:http://127.0.0.1:3000/nihao?name=%27naaa%27
//结果 为:
/*
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: '?name=%27naaa%27',
query: 'name=%27naaa%27',
pathname: '/nihao',
path: '/nihao?name=%27naaa%27',
href: '/nihao?name=%27naaa%27' }
*/
- 注意 : 1. 通过my_url.pathname 来用于if判断
2. query为字符串 并没有像express框架一样直接转成了对象!!!
所以 let my_url = url.parse(req.url,true); 加个true!!!!!
queryString模块
js文件
let http = require('http');
let queryString = require('queryString'); //用于处理post提交的数据转换成对象
let fs = require('fs');
http.createServer((req, res)=>{
// 先让'/'为html文件
if(req.url === '/'){
fs.read('posttest',(err,data)=>{
if(! err){
res.writeHead(200,{'Content-Type':'text/html;charset=UTF-8'});
res.end(data)
}
})
}
//接下来做post请求响应
if(req.url === 'posttest' && req.method.toLowerCase() === 'post'){
let shuju = '';
req.on('data',(data)=>{ // 监听 data变化 有点下vue中的watch方法,data每变化一次会 //执行一次函数
shuju += data; //数据流逐渐添加到shuju中,异步添加
})
req.once('end',()=>{ // req的传递都结束时,执行下边的函数
console.log(queryString.parse(shuju)) // 此时,数据都是字符串,需要让queryString来转成 // 对象来使用
res.end('上传完成');
})
}
}).listen(3000,'127.0.0.1')
js文件总结
1. req.on('data',function(data){})
作为监听的回调函数. 执行异步操作!! 分批次的将data数据传输进来
2. req.once('end',function(){})
当所有的数据传输完毕时,执行这个函数
req.once 和req.on 的异同:
- 相同: 都是用于事件监听
- 不同: once只执行一次 on可以无限次监听
html文件
<body>
<form action="/nodetest" method="post">
<input type="text" name="name" value=""><br>
<input type="password" name="psw" value=""><br>
<input type="radio" name="sex" value="1">:男
<input type="radio" name="sex" value="0">:女 <br>
<input type="file" name="img"> <br>
<input type="submit" value="提交">
</form>
</body>
原生get 和 post 表单提交总结
- get :通过url来来传值, 那么直接通过 req.url(这不算模块,默认就有的)l就可以获取传递过来的全部字符串信息… 只需要用 url模块 来提取各个功能的字符串对象,通过true来将字符串转成对象… **let data = url.parse(req.url, true)**让字符串转成对象, 然后 data.query就可以求取post传递的值
- post : post比较复杂. 不能通过url来得到需要的值, 那么就需要通过监听来获取传输文件**req.on(‘data’,(data)=>{})**来分批次获取传递的值,类似于vue中的watch方法. 总有全部传递完毕的时候,那么此时就需要对数据进行操作 req.once(‘end’,function(){ 传完时,做啥?? });
模板引擎
- npm art-template install --save
var template = require('art-template');
var str = `
{{each}}
{{ $value }}
{{/each}}
`
var nowrender = template.render(str,['你好','我不好'])
express框架
hello world
安装方法
- 安装node
- npm init -y ( 初始化packjson) -y是缩写
- npm install express --save 安装框架
let express = require('express');
let app = express();
app.get('/', (req, res)=>{
res.send('ok')
});
app.listen(3000,'127.0.0.1',()=>{
console.log('running!')
})
路由
api介绍
- app.get(’/’, function(req, res, next))
- app.post()
- app.use() : 接收get/post ajax请求
next()
- 中间件的前提条件
- next()就是一个函数,意思是这个函数代表执行下一个相同路由的内容,执行完成之后,又会回来执行next() 之后的内容,这个是原理 但是呢,一般也不会再next()函数之后写上代码!!!
let express = require("express");
let app = express();
app.get('/a',function(req, res, next){
next() // 当添加了这一行代码,才能够执行下边的get('/a')的代码块
})
app.get('/a',function(req, res, next){
})
express.Router()
const express = require('express');
const router = express.Router();
module.exports = router
/*************************************/
const router = require('./Router/router.js')
app.use(router)
// 当有多个路由js文件的时候,可以再次分开. 但是在url上就要加上/user 或者 /makesome了
app.use('/user'router1)
app.use('/makeSome'router2)
中间件
什么是中间件
中间件是干啥的
中间件的作用就是为了让ajax提交上来的信息先做一个预处理,不同的中间件预处理不同的信息,body-parser的作用是预处理常规post提交信息,multer处理的是FormDate上传的信息,express.static()处理的是判断你求取的是不是一个静态的文件,cookies-parser处理的是cookies过来的信息
中间件是怎么工作的
中间件是对上传上来的信息预处理, 不同的中间件提取不同的相对应的信息, 处理的方式用app.use(), 在第三方包(中间件)内部实现的是将需要的信息绑定在request对象上,通过next() 传递给下一个路由作为参数使用
静态资源 static中间件
- __filename : 当前执行的js文件
- __dirname : 当前执行的js文件的文件夹
app.use('/public' express.static(path.join(__dirname,'/publc')) )
-
作用: 使用静态文件夹 让文件夹里的文件可以直接通过url来访问
-
和原生的区别在于 : express会将相对路径自动转化为get请求,原生的并没有这个功能!!!
-
使用注意 : app.use(express.static(path.join(__dirname,url))) 要放在路由的后面
// express var express = require('express'); var app = express(); app.use('/public',express.static('./public')) app.listen(3000,'127.0.0.1',function(){ console.log('runing!!'); }) // 原生 var http = require('http'); var fs = require('fs'); var url = require('url'); var url1 = url.parse(req.url); var pathname = url1.pathname; fs.readFile('./public/index.html',function(err,data){ res.end(data); }) } }).listen(3000,'127.0.0.1',function(){ console.log('runing!!'); })
body-parser中间件
-
express中可以直接使用req.query来获取上传get数据,但是post却不行,需要用到中间件
-
通过在app.use来预处理数据,再通过next()传递给app.post()来直接使用,使用的过程中要遵循别人框架的规则
const express = require('express'); const body = require('body-parser'); let app = express() app.use(body.urlencoded({ extended : false })) app.post('/reg',(req, res)=>{ console.log(req.body) }) app.listen(3000,'127.0.0.1')
body-parser底层原理
var queryString = require('querystring') //parse()方法时把字符串转化成对象 // app.use这代表所有的路由都要经过这,接着用next()传递下去 app.use((req, res, next)=>{ let str = ''; req.on('data',buffer=>{ str += buffer; }) req.on('end',()=>{ req.body = querystring.parse(str.toString()) // 把解析出来的值赋值给req.body next() // 传递到下一个路由 }) }) app.post('/login',(req,res)=>{ console.log(req.body) })
multer中间件
-
获取上传的文件中间件
-
multer处理Form-data数据的
// 导入中间件模块 const multer = require('multer'); let upload = multer({dest : './static/upload'}) // 设置上传到哪里 // avatar代表上传文件的name的名字 app.post('/profile', upload.single('avatar'), function (req, res, next) { console.log(req.file ) // req.file : 上传的文件 req.file.filename ===> 上传文件后的名字 console.log(req.body ) // 代表除了file中的其它信息 })
cookie-parser中间件
什么是cookie
-
cookie是做啥的?
用于保存用户信息(通常指登录信息 / 购物车)
-
例子 : 当访问网易云课堂,第一次账户密码登录. 服务器会向浏览器发送cookie信息, 这个cookie会存储在浏览器,存储什么信息由服务器自己决定,当下次再次访问这个网站的时候,浏览器会自动带上cookie发送到浏览器.用于验证你是否在规定的期限内登录过.要是没有携带cookie或者cookie的保存时间已经过了,那么就需要重新登录,重新让服务器向你的浏览器发送信息.
注意点 :
- cookie必须要设置存放的时间,不设置的话默认关闭浏览器就自动消失
- cookie的大小不能超过4K
-
例子1 : hello world — 验证简单的账号密码
const express = require('express');
// 导入中间件模块
const cookieParser = require('cookie-parser');
const app = express();
// 设置静态文件
app.use(express.static('./public'))
// 设置中间件
app.use(cookieParser())
// 声明用户存储的数据
let obj = {
龚利明 : {username : '龚利明',age: 18,sex : '男'},
江华 : {username : '江华',age: 28,sex : 'nv'}
}
// 提交登录按钮提交到这
app.get('/login',(req, res)=>{
// 判断用户1 账号密码是否正确
if(req.query.username == '龚利明' && req.query.psw == '123456'){
// 正确返回cookie,及正确的提示
res.cookie('username','龚利明',{maxAge : 100000})
res.send('登录成功!')
}
// 判断用户1 账号密码是否正确
else if(req.query.username == '江华' && req.query.psw == '654321'){
//res.cookie(传递对象,对象的值,属性操作)
res.cookie('username','江华',{maxAge : 100000})
res.send('登录成功!')
} // 账号密码不正确
else{
res.send('账号或者密码错误,请重新输入!')
}
})
// 登录主页面,默认执行ajax请求
app.get('/lists',(req, res)=>{
// 获取当前的cookie及上传的用户名
const username = req.cookies.username
// 验证成功.返回数据
if(username != undefined){ // 当cookie过期,或者没有注册值为underfine
res.send({
code : 200,
username : obj[username]
})
}
// 验证失败
else{
res.send({
code : 404,
})
}
})
app.listen(3000,()=>{
console.log('running!');
})
升级版本
const express = require('express')
const cookieParser = require('cookie-parser');
let app = express()
app.use(cookieParser(
'dasdaskdhaslkdjkl' // 设置签名
));
app.get('/a',(req, res) => {
console.log(req.cookies) // 获取传递过来的cookies
res.cookie('money',998,{ //返回设置cookie
maxAge : 14 * 86400 * 1000 // 最大存储时间
,domain : 'baidu.com',
path : '/uesr', // 当访问这个服务器且路由为/user才会携带cookie
signed : true, // 设置签名
httpOnly : true, //客户端将无法通过document.cookie读取到 COOKIE 信息,可防止 XSS 攻击产生
secure : true // 设置为true只能用https
})
})
signed 设置签名
- cookie可以直接在浏览器中让人查看到,因此为了让别人看不懂服务器给你浏览器发送的信息的意义,就变相的把值进行转码,浏览器上的cookie值就是转码之后的值. 执行步骤的话主要是三步 :
- 设置 cookie 参数对象的 signed = true
- 设置签名标识用来对cookie数据做签名使用==> 在中间件中直接加入任意的字符串,不能为中文serverApp.use(cookieParser(‘签名用的 标识数据字符串’));
- 服务器端接收传过来的cookie的值得时候,要用新的API接收, 需要使用
request.signedCookies
注意:被篡改的签名 cookie 会被服务器拒绝,并且 cookie值会重置为它的原始值
// 第二步 : 设置任意的随机字符串
app.use(cookieParser('nihaowoshinibaba'))
let obj = {
龚利明 : {username : '龚利明',age: 18,sex : '男'},
江华 : {username : '江华',age: 28,sex : 'nv'}
}
app.get('/lists',(req, res)=>{
// 第三步 使用signedCookies来接收
const username = req.signedCookies.username
console.log(username);
if(username != undefined){
res.send({
code : 200,
username : obj[username]
})
}else{
res.send({
code : 404,
})
}
})
app.get('/login',(req, res)=>{
if(req.query.username == '龚利明' && req.query.psw == '123456'){
// 第一步 : 设置signed为true
res.cookie('username','龚利明',{maxAge : 100000,signed:true})
res.send('登录成功!')
}
else if(req.query.username == '江华' && req.query.psw == '654321'){
res.cookie('username','江华',{maxAge : 100000, signed:true})
res.send('登录成功!')
}else{
res.send('账号或者密码错误,请重新输入!')
}
})
hash密码保存
为啥要用 :
- 直接在数据库中存储密码是非常不安全的,那么我们可以用类似于上边的signed来进行转码, 然后再存储到服务器保存,但是转换乱码之后转换不回来了,不过一样的值转换的效果是一样的,因此,每次从客户端接收到数据,都可以先进行转码,然后再去服务器作对比,然后进行操作
简单介绍 :
- hash算法:可以将任意数据 生成 固定长度的16进制字符串 并且,只要数据一样,那么不管计算多少次都会获得同一个 16进制字符串
使用 :
-
安装第三包 : npm i hash.js -D
const hash = require('hash.js'); let password = 123456; //将 密码 转成 sha256 的hash值字符串 64位 password = hash.sha256().update(password).digest('hex'); // 结果:‘8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92’
模板引擎
- __dirname 指的是当前目录的绝对路径
- 通过path模块来拼接路径 path.join(__dirname + ‘views’)
// 1. 导入模板引擎包
npm install ejs --save
// 2. 创建views文件夹及.ejs文件
// 3. 在js入口文件设置模板引擎
let path = require('path')
app.set('views', path.join(__dirname + '/views')) //设置模板引擎的文件夹所在的位置
app.set('view engine', 'ejs') //设置使用的模板引擎为 ejs
// 4. 调用 res.render()
router.get('/',(req, res)=>{
res.render(index,{lists:[1,2,3,4]})
})
- ejs代码
<body>
<% for(var i = 0; i < lists.length; i++){ %>
<div><%= lists[i] %></div> // 注意着有 = 号
<% } %>
</body>
获取用户的ip地址
req.params
- 作用: 获取url中的某一部分的后面url
url为: 127.0.0.1:3000/fuck/make/18
router.get('/fuck/:name/:age',(req, res)=>{
console.log(req.params.name) // 结果为 : make
console.log(req.params.age) // 结果为 : 18
})
response对象
res.redirect()
- 重定向
- 使用方法
- res.redirect(URL) ==> URL 写上就好了,前提是之前定义了url的get请求
res.send()
- 和原生的nodejs相比, send和end区别大大的!!!
- 不同点 : res.send() 不再需要添加Content-Type,这里可以直接使用,能够自动识别 JSON / HTML 等都可以自己识别, 直接返回就好啦!
- 相同点 : res.send()和res.end() 都只能使用一次
res.status()
- 返回状态码
res.download()
- 返回下载文件
res.download(传递的文件路径, 传递过去之后的名字)
--app.js代码------------------------------------------------------------
const express = require('express');
const app = express();
const path = require('path')
app.use(express.static(path.join(__dirname , './public')))
app.get('/down',(req,res)=>{
res.download('./download/news.txt','你好.txt')
})
app.listen(3000,()=>{
console.log('开启成功');
})
--html代码----------------------------------------------------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./jquery-1.12.4.js"></script>
</head>
<body>
<button>
下载
</button>
<script>
$(function(){
$('button').click(function(){
// 不用通过ajax来请求,我也不懂为啥,ajax就是不行
// $.ajax({
// type : 'get',
// url : 'http://127.0.0.1:3000/down',
// success : function(data){
// console.log(data);
// }
// })
location.href = 'http://127.0.0.1:3000/down';
})
})
</script>
</body>
</html>
generator 应用生成器
- npm i express-generator -g ==> 安装应用生成器在全局
- express --view=ejs demo ==> 设置模板引擎为ejs模式
路径总结
不管是绝对路径还是相对路径都是可以用的但是要遵循以下规则
假设服务器默认为http://127.0.0.1:3000
下图是层级结构,且public文件夹设置为静态文件夹
[外链图片转存失败(img-mNZEItvu-1568960271765)(/路径总结.png)]
-
当index.html文件要src引入img文件夹下的1.png时 :
// 1. 使用绝对路径,绝对路径必须直接在端口号后边拼接 // http://127.0.0.1:3000 + /img/1.png === http://127.0.0.1:3000/img/1.png <img src="/img/1.png" alt=""> // 2. 使用相对路径,相对路径发送的url会自动将该文件补全成绝对路径,因为index.html已经处于 // 一级目录了,因此发送的url为: http://127.0.0.1:3000/img/1.png <img src="./img/1.png" alt=""> // 3. 使用相对路径, 只要是已经达到了 一级目录,再多的../都是始终保持在一级目录 <img src="../../img/1.png" alt="">
- 当login.html文件要src引入img文件夹下的1.png时
// 1. 使用绝对路径,发送的请求直接拼接在端口号后边 // http://127.0.0.1:3000 + /img/1.png === http://127.0.0.1:3000/img/1.png <img src="/img/1.png" alt=""> // 2. 使用相对路径, 这里的 ../ 会退到上级目录, 此时发现这个url已经在一级目录了 <img src="../img/1.png" alt="">
总结 :
- 当需要数据库存储文件路径的url作为数据时,也就是这个文件想在不同的html文件调用的时候,建议使用绝对路径.!!!
因为不同层级目录下的html文件所指向需要的同一个文件的相对路径是不一样的 - 当这个文件并不是大家都需要加载引用的,仅仅是一个html文件要用的.也可以使用相对路径
- 作为文件路径方式打开的html页面只能使用相对路径,绝对路径是没用的, 但是VScode有live Server插件,打开的时候可以作为服务器静态文件打开
mysql
安装
- 安装mysql软件,结合Navicat可视化工具来使用,具体安装步骤在我的u盘说明文档有
可视化工具的使用
- 连接mysql 打开localhost3306 右键创建数据库 字符集和数据格式都选择utf-8的格式
- 右键表格,点击创建表格, id要加主键 并且不为null 而且勾选自动递增 点击保存
- 选中数据库 ==> 点击查询 ==> 新建查询 ==> 在这里编写sql代码
注意 : 主键 : 表示唯一性, 不可改变,当输入的id值重复时,会自动报错
sql语法
增加 insert
- insert into Strdents (姓名,性别,出生日期) values (‘开心朋朋’,‘男’,‘1980/6/15’)
//添加单条
INSERT INTO student (name, age, sex, phone) VALUES('aaa',23,'a111','22223')
//添加多条
INSERT INTO student (name, age, sex, phone) VALUES('aaa',23,'a111','22223'),('bbb',23,'bbbb','44444')
删除
- delete from 表名 where 删除条件
delete from a where name='龚利明'(删除表a中列值为开心朋朋的行)
更新
- update 表名 set 列名=更新值 where 更新条件
//
update tongxunlu set 年龄=18,姓名='龚利明' where 姓名='蓝色小名'
查询
- select 列名 from 表名 where 查询条件表达试 order by 排序的列名asc(升序)或desc(降序)
// 查询a中所有数据行和列
select * from a
// 查询表a中f=5的所有行,并显示i,j,k3列
select i,j,k from a where f=5
// 查询a表中性别为男的所有行,显示name列,并将name列改名为(姓名)显示
select name as 姓名 from a where xingbie='男'
// 查询表a中email为空的所有行,并显示name列;SQL语句中用is null或者is not null来判断是否为空行
select name from a where email is null
// 查询表a,显示列name的前6行,top为关键字
select top 6 name from a
// 查询显示表a中,name字段第一个字为赵的记录
select * from a where name like '赵%'
// 查询表a中address值为北京或者上海或者唐山的记录,显示name字段
select name from a where address in ('北京','上海','唐山')
nodejs中使用sql
- 安装第三方模块
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost', // ip地址
user : 'me', // 用户名
password : 'secret', // 密码
database : 'my_db' // 数据库名字
});
connection.connect();
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (!error) {
console.log('The solution is: ', results);
}
});
connection.end();
webpack
安装
- npm i webpack -g
- npm i webpack-cli -g
hello world
1.准备 :
- 一个项目工程文件
- 工程文件内一个webpack.config.js文件
- 创建一个src用于存放想要打包的代码
- webpack.config.js代码如下
const path = require('path');
module.exports = {
mode : 'development', //(开发模式) 或者 production(生产模式) 或者 none(只打包就好)
entry : { // 多入口
login : './src/js/login.js',
register : './src/js/register.js'
}
output : {
path : path.resolve(__dirname,'build') // 创建用于存放打包好的文件夹
filename : '[name].min.js' // 设置打包好的文件夹的名字
}
}
- 在项目工程化 cmd界面输入 webpack即可打包文件
loader
style-loader css-loader (css样式)
- 上边的内容仅仅只能打包js代码,却不能打包css代码等, 要想打包css代码也必须要有相对应的包
- 安装
- npm i style-loader -D
- npm i css-loader -D
- 在m1.js文件下导入编写好的css
import $ from 'jquery';
import '../src/css/index.css'
- webpack.config.js代码如下
const path require('path');
module.exports = {
mode : 'production',
entry : './src/m1.js',
output : {
path : path.resolve(__dirname,'build'),
filename : 'bundle.min.js'
},
module : {
rules : [
{test : /\.css$/, use : ['style-loader','css-loader']} // 加载顺序必须是style在前
]
}
}
- css-loader的作用 : 为了让webpack能够识别这个是css文件
- style-loader的作用 : 当html文件引入了m1文件时,能够在header中添加一个style标签,并且把样式放在里边
postcss-loader autoprefixer (css兼容处理)
- 导入包 :
- npm i postcss-loader -D
- npm i autoprefixer -D
- 介绍 :
- postcss-loader : 为了能够读取css的样式,配合autoprefixer来编写兼容样式
- autoprefixer : 实现css样式的兼容性
- 代码编写
- webpack.config.js文件 :
const path = require('path');
module.exports = {
mode : 'development',
entry : './src/js/main.js',
output : {
path : path.join(__dirname, 'build'),
filename : 'main.min.js'
},
module : {
rules : [
{test : /\.css$/, use : ['style-loader','css-loader','postcss-loader']}
// 作用顺序从右到左,不能变
]
}
}
- postcss.config.js :
module.exports = {
plugins : [
require('autoprefixer')
]
}
less less-loader (less使用)
-
安装包 : npm i less -D
npm i less-loader -D
-
webpack.config.js文件 :
const path = require('path')
module.exports = {
mode : 'development',
entry : './src/app.js'
output : {
path : path.resolve(__dirname,'build'),
filename : 'main.min.js'
},
module : {
rules : [
{test : /\.css/, use : ['style-loader','css-loader','postcss-loader']}
{test : /\.less/, use :['style-loader','css-loader','less-loader']}
// 顺序不能乱,从右边开始执行
]
}
}
url-loader file-loader(文件处理)
-
安装 : npm i file-loader -D
npm i url-loader -D
-
使用说明 :
- 使用url-loader的前提是必须安装file-loader, file-loader能做的,url-loader都能做
- webpack打包只会将用的到的文件拿来打包,所以必须在css等文件中引入(待考证? js中通过字符串加载的如何使用? 获取还有其他loader包)
-
less文件路径 : src/main.less
body {background : url('./test.png') norepeat}
- webpack.config.js 文件 :
const path = require('path')
module.exports = {
mode : 'development',
entry : './src/app.js',
output : {
path : path.resolve(__dirname, 'build'),
filename : 'main.min.js',
},
module : {
rules : [
{test : /\.css$/, use : ['style-loader','css-loader','postcss-loader']},
{test : /\.less$/, use : ['style-loader','css-loader','less-loader']},
{
test : /\.(png|jpg)$/i, use : {
loader : 'url-loader',
options : {
outputPath : 'imgs',
limit : 0
}
}
}
]
}
}