前后端交互

URL(统一资源定位符):由客户端与服务器端的通信协议,存有该资源的服务器名称,资源在服务器的具体存放位置三部分组成
查询字符串:URL地址后面拼接的参数,URL末尾为?后加参数=值,多个参数用&分隔
编码函数:encodeURL()
解码函数:decodeURL()
资源获取:请求-处理-响应(请求需要用到XMLHttpRequest对象)

  • 请求方式:
    • get(获取服务器资源)
    • post(向服务器提交数据发送资源)

接口:使用Ajax请求数据时被请求的URL地址叫做数据接口,每个接口必须有请求方式
接口文档:接口名称,接口URL,调用方式,参数格式(参数名称,参数类型,是否必选,参数说明),响应格式(数据名称,数据类型,说明),返回示例(可选)
表单(数据采集,发送到服务器):由表单标签form,表单域input,表单按钮button三部分组成(表单域包括文本框、密码框、隐藏域、多行文本框、复选框、单选框、下拉选择框、文本上传框)
表单同步提交:点击submit按钮触发表单提交从而使页面跳转到actionURL的行为(提交后发生跳转用户体验差,页面之前状态和数据丢失)
表单同步提交解决方案:表单只负责采集数据,Ajax负责提交数据
监听表单提交事件:$(标签).submit(function(){})$(标签).on('submit', function(){})
阻止表单默认提交行为(一次性获取表单中所有数据,必须为每个表单元素添加name属性):event.preventDefault()
获取表单中数据:$(标签).serialize()
模板引擎:art-template(根据模板结构和数据生成完整页面)

  • 模板引擎使用:
    • 导入art-template:<script src="template-web,js"></script>
    • 定义数据:var 对象名 = {属性:'值'}
    • 定义模板:{{属性名}}
    • 调用template函数:var 变量名 = template('选择器', 对象名)
    • 渲染HTNL结构:$(标签).html(变量名)

标准语法:{{数据}}(输出变量,对象属性,三元表达式,逻辑或,加减乘除等表达式)
标准语法-原文输出:{{@ 数据}}(数据携带html标签需要原文输出,不会转义标签)
标准语法-条件输出:{{if 条件}}条件达成输出内容{{/if}} {{if 条件1}}条件1达成输出内容{{else if 条件2}}条件2达成输出内容{{/if}}
标准语法-循环输出:{{each 数组名}} {{$index}} {{$value}} {{/each}}
标准语法-过滤器(类似管道操作符,上一个输出作为下一个输入):{{函数名 | dateFormat}}
template.defaults.imports.dateFormat = function(){return 值}

  • HTTP请求消息:由请求行,请求头部,空行,请求体4部分组成
    • 请求行:请求方式,URL,HTTP协议版本三部分,空格隔开
    • 请求头部:多行键值对组成,键和值之间冒号分隔
    • 请求体:只有post请求有,get请求没有
  • HTTP响应消息:由状态行,响应头部,空行,响应体4部分组成
    • 状态行:HTTP协议版本,状态码,状态码描述文本3部分,空格隔开
    • 响应头部:多行键值对组成,键和值之间冒号分隔
    • 响应体:服务器响应浏览器的内容
  • 请求方法:
    • 查询:GET
    • 新增:POST
    • 修改:PUT
    • 删除:DELETE
  • 状态码(三个十进制数字,第一个数字定义类型)
    • 信息(少遇到):1**
    • 成功:2**(200:请求成功用于post或get,201:已创建用于post或put)
    • 重定向:3**(301:资源永久移动,302:资源临时移动,304:资源未修改)
    • 客户端错误:4**(400:请求服务器无法理解或有误,401:请求需用户验证,403:请求理解但服务器拒绝执行,404:服务器无法找到资源,408:请求超时)
    • 服务器错误:5**(500:服务器内部错误,501:服务器不支持请求方法,503:系统维护或超载)

同源:协议,域名,端口相同的页面,Ajax只能在同源客户端和服务器之间发送请求
跨域请求方案:JSONP和CORS

  • JSONP(临时性方案,只支持get请求,不属于Ajax请求)

    • 已经配置CORS跨域共享则必须在CORS中间件前声明JSONP接口

    • 优先创建JSONP接口:app.get('/api/jsonp', (req, res) => {})

    • 在配置CORS中间件:app.use(cors())

    • jQuery中实现JSONP:动态创建移除<script>标签,请求时创建,成功时移除

    • 实现JSONP接口步骤:

      • 获取客户端发送回调函数名字
      • 得到以SONP形式发送给客户端数据
      • 拼接处函数调用字符串
      • 拼接所得字符串响应给客户端<script>标签解析执行
      • jsonp 是解决跨域的一种解决方案,实现原理主要是利用动态创建 script 标签,设置src属性,页面要提前定义好callback。后端会返回回调函数执行,并包裹参数callback(data) callback 中的参数就是 json
  • 在vue 中主要是通过vue 脚手架中的vue.config.js 文件来配置的,通过在devServer中的proxy来配置跨域的前缀

  • 中转或者叫服务代理


app.get('/api/jsonp', (req, res) => {
  const funcName = req.query.callback
  const data = {属性: '值', 属性: '值'}
  const scriptStr = `${function}(${JSON.stringify(data)})`
  res.send(scriptStr)
})

CORS(使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息)


服务器端响应的数据格式

XML(可扩展标记语言):格式臃肿,无关代码多,体积大,传输效率低,JavaScript中解析麻烦

  • JSON(JavaScript对象和数组的字符串,服务器相应数据主要对对象):轻量级文本数据交换格式,专门用于存储和传输数据,比XML更小、更快、更易解析,主流格式
    • 对象结构:{key:value,key:value}(key必须是英文双引号包裹,value可以使数字、字符串、布尔值、null、数组、对象六种类型)
    • 数组结构:[“数据”, “数据”](数据可以使数字、字符串、布尔值、null、数组、对象六种类型)

反序列化(字符串转换为数据对象):JSON.parse();(将json字符串转换为json对象)
序列化(数据对象转换为字符串):JSON.stringify();(将json对象转换为json字符串)
真实项目,服务器端大多数情况下会以 JSON 对象作为响应数据的格式。当客户端拿到响应数据时,要将 JSON 数据和 HTML 字符串进行拼接,然后将拼接的结果展示在页面中。


原生Ajax

1 创建 xhr 对象

var xhr = new XMLHttpRequest();

2 告诉 Ajax 请求地址以及请求方式

xhr.open('get', 'http://www.example.com');

3 获取服务器端给与客户端的响应数据(responseText获取服务器返回数据)

xhr.onload = function () {
    console.log(xhr.responseText);
}

4 发送请求

xhr.send();

jQuery 中的 Ajax($.get(),$.post(),$.ajax()

$.get(请求资源地址, 请求期间携带参数, 请求成功时的回调函数)(资源地址必选,为string型参数,携带参数和回调函数非必选,携带参数类型为Object)
$.post(提交数据地址, 提交数据, 数据提交成功时的回调函数)(提交数据地址必选,为string型参数,提交的数据和回调函数非必选,携带参数类型为Object)

发送Ajax请求:$.ajax()

$.ajax({
    type: 'get/post',(请求方式,必写)
    url: 'http://www.example.com',(请求地址,必写)
    data: { name: 'zhangsan', age: '20' },/'name=zhangsan&age=20'/JSON.stringify({name: 'zhangsan', age: '20'})(请求携带数据,必写)
    contentType: 'application/x-www-form-urlencoded',/'application/json'
    beforeSend: function () { (请求前调用)
        return false
    },
    success: function (response) {},(请求成功后调用:success,必写)
    error: function (xhr) {}(请求失败后调用:success)
});

发送jsonp请求:$.ajax()

$.ajax({
    method:'GET",
    url: 'http://www.example.com',
    dataType: 'jsonp',(指定当前发送jsonp请求)
    jsonp: 'cb',(修改callback参数名称)
    jsonCallback: 'fnName',(指定函数名称)
    success: function (response) {} 
})

请求参数传递

GET 请求方式:xhr.open('get', 'http://www.example.com?name=zhangsan&age=20');
POST 请求方式(Content-Type固定写法):xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') xhr.send('name=zhangsan&age=20');(Content-Type 属性的值是 application/json)
get 请求是不能提交 json 对象数据格式,只能提交application/x-www-form-urlencoded格式,传统网站的表单提交也是不支持 json 对象数据格式


Ajax 状态码

0:请求未初始化(XMLHttpRequest对象已创建,还没有调用open())
1:请求已经建立,但是还没有发送(已调用open(),还没有调用send())
2:请求已经发送(调用send(),响应头已被接收)
3:请求正在处理中,通常响应中已经有部分数据可以用了
4:响应已经完成,可以获取并使用服务器的响应了
xhr.readyState(获取Ajax状态码)
Ajax 状态码变化时触发事件:onreadystatechange
xhr.status(获取http状态码)
网络中断触发xhr对象下面的onerror事件


全局事件(Ajax请求被发送时,触发对应的全局事件)

请求开始发送时执行(监听当前文档所有Ajax请求,并在ajaxstart的callback中显示loading效果):$(document).ajaxStart()
请求结束发送时执行(监听当前文档所有Ajax请求,并在ajaxstart的callback中隐藏loading效果):$(document).ajaxStart()
请求完成时触发:.ajaxComplete()
将不同源的服务器端请求地址写在 script 标签的 src 属性中

服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。
const data = ‘fn({name: “张三”, age: “20”})’;
res.send(data);
在客户端全局作用域下定义函数 fn
function fn (data) { }
在 fn 函数内部对服务器端返回的数据进行处理
function fn (data) { console.log(data); }


fetch

axios(网络数据请求库)最好用

axios.get/post(‘URL地址’, 数据对象).then(callback)

    axios({
        method: '请求类型',(请求方式,必写)
        url: 'http://www.example.com',(请求地址,必写)
        params/data: { name: 'zhangsan', age: '20' },(get参数通过params属性提供,post参数通过data属性提供,必写)
        },
    }).then(function(res){})

模板引擎:art-template

    下载命令:npm install art-template
    引入模板引擎:const template = require('art-template')
    拼接:const html = template('模板路径', 数据);
    模板语法:art-template支持标准语法和原始语法,标准语法容易读写,原始语法具有强大的逻辑处理能力
        标准语法:{{数据}}
        原始语法:<%=数据%>
        原文输出:数据携带html标签,不会转义标签
            标准语法:{{@数据}}
            原始语法:<%-数据%>
        条件判断:
            标准语法:{{if(条件)}}条件达成输出内容{{/if}} / {{if(条件1)}}条件1达成输出内容{{else if(条件2)}}条件2达成输出内容{{/if}}
            原始语法:<%if(条件){%>条件达成输出内容<%}%> / <%if(条件1){%>条件1达成输出内容<%}else if(条件2){%>条件2达成输出内容<%}%>
        循环:
            标准语法:{{each target}} {{$index}} {{$value}} {{/each}}
            原始语法:<%for(var i = 0; i<target.length; i++){%> <%= i %> <%= target[i] %> <%}%>
        子模板:抽离公共区块到单独文件,模板为art文件,模板路径为相对路径
            标准语法:{{include '模板路径'}}
            原始语法:<%include ('模板路径')%>
        导入模板变量:
            template.dafaults.imports.变量名 = 变量名;(添加到函数内)
            $imports.变量名称(添加到标签内)
        模板继承:先在html骨架文件中放入{{block '名字'}}{{/block}}然后在需要做的文档中放入{{block '名字'}}内容{{/block}},{{extend '路径/文件名'}}指继承的文件
        模板配置:向模板中导入变量template.defaults.imports.变量名 = 变量值,再设置模板根目录template.defaults.root = 模板目录,最后设置模板默认后缀template.defaults.extname = '.art'

<!-- 请求头:origin: http://localhost:3000
响应头:Access-Control-Allow-Origin: 'http://localhost:3000'
    Access-Control-Allow-Origin: '*'
    Access-Control-Allow-Methods:get/post
withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false
Access-Control-Allow-Credentials:true 允许客户端发送请求时携带cookie -->





            原始语法:<%-数据%>
    下载命令:npm install art-template
    引入模板引擎:const template = require('art-template')
    拼接:const html = template('模板路径', 数据);
    模板语法:art-template支持标准语法和原始语法,标准语法容易读写,原始语法具有强大的逻辑处理能力

        子模板:抽离公共区块到单独文件,模板为art文件,模板路径为相对路径
            标准语法:{{include '模板路径'}}
            原始语法:<%include ('模板路径')%>
        导入模板变量:
            template.dafaults.imports.变量名 = 变量名;(添加到函数内)
            $imports.变量名称(添加到标签内)
        模板继承:先在html骨架文件中放入{{block '名字'}}{{/block}}然后在需要做的文档中放入{{block '名字'}}内容{{/block}},{{extend '路径/文件名'}}指继承的文件
        模板配置:向模板中导入变量template.defaults.imports.变量名 = 变量值,再设置模板根目录template.defaults.root = 模板目录,最后设置模板默认后缀template.defaults.extname = '.art'

设置http请求时限(超时自动停止):xhr.timeout = 毫秒数
xhr.ontimeout = function(event){}

<!-- 获取响应头中数据:xhr.getResponseHeader -->
<!-- 客户端模板引擎art-template -->
<!-- https://aui.github.io/art-
    mplate/zh-cn/index.html -->

<!-- FormData 对象的作用(省略表单控件获取、控件值获取、参数格式拼接,异步上传二进制文件) -->
<!-- 1.   准备 HTML 表单
    <form id="form">
        <input type="text" name="username" />
        <input type="password" name="password" />
        <input type="button"/>
    </form>
2.   将 HTML 表单转化为 formData 对象
    var form = document.getElementById('form'); 
    var formData = new FormData(form);
3.   提交表单对象
    xhr.send(formData);
(Formdata 对象不能用于get请求、因为对象需要被传递到send方法中,formData 对象需要使用formidable模块进行解析)
获取表单对象中属性的值: formData.get('key');
设置表单对象中属性的值: formData.set('key', 'value');(属性名已存在会覆盖)
删除表单对象中属性的值: formData.delete('key');
向表单对象中追加属性值: formData.append('key', 'value');(属性名已存在会追加)
保留上传文件后缀名:form.keepExtensions = true(true保留,false不保留)
二进制文件上传:
    <input type="file" id="file"/>
    var file = document.getElementById('file')
    file.onchange = function () {(当用户选择文件的时候)
        var formData = new FormData();(创建空表单对象)
        formData.append('attrName', this.files[0]);(将用户选择的二进制文件追加到表单对象中)
        xhr.open('post', 'www.example.com');(配置ajax对象,请求方式必须为post)
        xhr.send(formData);
    file.onchange = function () {(当用户选择文件的时候)
        xhr.upload.onprogress = function (ev) {(文件上传过程中持续触发onprogress事件)
            bar.style.width = (ev.loaded / ev.total) * 100 + '%';(将结果赋值给进度条的宽度属性,ev.loaded(当前上传文件大小)/ev.total(文件总大小)将结果转换为百分数)
        }
    }
文件上传图片即时预览:
    xhr.onload = function () {
    var result = JSON.parse(xhr.responseText);
    var img = document.createElement('img');
    img.src = result.src;
    img.onload = function () {
        document.body.appendChild(this);
        }
    } -->




<!-- $.get()、$.post()方法($.get方法用于发送get请求,$.post方法用于发送post请求,response服务器返回的参数) -->
<!-- $.get('http://www.example.com', {name: 'zhangsan', age: 30}, function (response) {})
$.post('http://www.example.com', {name: 'lisi', age: 22}, function (response) {}) -->



<!-- 纳米级进度条插件:NProgress -->
<!-- <link rel='stylesheet' href='nprogress.css'/>
<script src='nprogress.js'></script>
进度条开始运动:NProgress.start();
进度条结束运动:NProgress.done(); -->



<!-- XML(全程为extensible markup language,代表可扩展标记语言,可以传输和存储数据,标签可自由定义) -->
<!-- <students> 
    <student>
        <sid>001</sid>
        <name>张三</name>
        </student>
    <student>
        <sid>002</sid>
        <name>王二丫</name>
        </student>
</students> -->

<!-- XML DOM(即XML文档对象模型,是w3c组织定义的一套操作XML文档对象的API。浏览器会将XML文档解析成文档对象模型) -->
<!-- 响应头类型:content-type
响应头:text/xml -->
<!-- 获取服务器返回xml数据:xhr.responseXML -->

<!-- serialize方法(将表单中的数据自动拼接成字符串类型的参数)
var params = $('#form').serialize(); -->

数组过滤方法:filter

Node(基于Chrome V8引擎的js代码运行环境)

官网:https://nodejs.org/en/
查看node版本号:终端输入node -v
模块化开发:一个js文件就是一个模块,模块内部定义的变量和函数默认情况下外部无法得到,模块内部使用exports对象进行成员导出,使用require方法导入其他模块

  • fs模块:用来操作文件的模块
    • fs文件系统模块导入:const fs = require(‘fs’)
      • 指定文件读取内容:fs.readFile(文件路径 , 编码格式, 回调函数)(路径和函数必选,函数err为null读取成功)
      • 指定文件写入内容:fs.writeFile(‘文件路径’, 写入内容, 写入内容格式, 回调函数)(路径、写入内容和函数必选,函数err为null读取成功)
  • path模块:处理路径模块
    • path路径模块导入:const path = require(‘path’)
      • path.join(‘路径名1’, ‘路径名2’)(路径拼接)
      • path.basename(路径字符串, 文件扩展名, )(获取路径中文件名)
      • path.extname(路径字符串)(获取路径中扩展名)
  • http模块:创建一个web服务器提供web服务
    • web服务器实例创建:const server = http.createServer()
    • 绑定事件:server.on(‘事件’, (req, res) => {})(req是请求对象包含客户端数据和属性,res是响应对象包含服务器数据和属性)
    • 启动服务器:server.listen(端口号, () => {})
  • 自定义模块:require()加载时必须指定./或…/开头的路径标识符
  • 第三方模块/包:团队成员分享文件过大删除,只保留package.json文件
    • 下载安装:终端输入npm install 模块名称或npm i 包名
    • 指定下载安装:终端输入npm i 模块名称@版本号
    • node_modules文件夹:存放所有已安装包
    • package.json文件夹:记录node_modules目录下每个包下载信息(dependencies节点记录包的安装记录)
    • 创建package.json文件:npm init -y
    • 一次性安装所有所需包:npm install(自动读取package.json中dependencies节点进行下载)
    • 卸载指定包:npm uninstall 包名称
    • 安装指定包并记录到devDependencies节点:npm i 包名 -D(devDependencies节点中包项目上线后不需要,dependencies节点中包项目上线开发都要用)
    • 切换npm下包镜像源(npm默认下载在国外下载速度较慢):
      • 查看/检查下包镜像源:npm config get registry
      • 切换下包镜像源:npm config set registry=https://registry.npm.taobao.org/
    • 快速查看切换下包镜像源:nrm
      • nrm安装为全局可用工具:
      • 查看所有可用镜像源:nrm ls
      • 切换镜像源:nrm use taobao
  • 安装i5thing_toc(md文档转html页面小工具):npm install -g i5thing_toc(将i5thing_toc安装为全局包)
  • 调用i5thing_toc:i5thing_toc -f 要转换的md文件路径 -o

开发私人包:文件夹下新建package.json(包管理配置文件),index.js(包入口文件),README.md(包说明文档)
登录npm账号:终端执行npm login命令,输入用户名、密码、邮箱
发布包:npm publish
删除已发布包:npm unpublish 包名 --force(只能删除72小时内的包,删除的包24小时不允许重复发布)


express框架

导入:const express = require(‘express’)
创建web服务器:const app = express()
启动服务器 :app.listen(端口号, () => {})
监听请求:app.get/post(‘客户端请求地址’, () => {res.send({})})
内容响应给客户端:res.send()
获取客户端发送到服务器端携带参数:req.query
获取URL中通过:匹配到的动态参数:req.params
创建静态资源服务器:express.static()

  • 监听项目变动自动重启项目工具:nodemon
    • 安装:npm install -g nodemon
    • 使用:nodemon 文件名
      路由:客户端请求与服务器处理函数之间的映射关系,分别是由请求类型,请求URL地址,处理函数3部分组成
      挂载路由:app.get/post(URL地址, 处理函数)
  • 模块化路由:
    • 创建路由模块对应js文件
    • 调用express.Roueter()函数创建路由对象
    • 路由对象挂载具体的路由
    • 使用module.exports向外共享路由对象
    • 使用app.use()函数注册路由模块
      中间件:function处理函数(形参列表包含next参数,多个中间件共享一份req和res,可以上游为req和res添加属性或方法下游使用)
      next函数作用:多个中间件连续调用关键,负责转交流转关系给下一个中间件或路由
      全局生效中间件:app.use(中间件函数)
      全局生效中间件简化形式:app.use((req, res, next)=>{next()})
      局部生效中间件:app.get(地址, 中间件函数, ()=>{})
      多个局部生效中间件:app.get(地址, 中间件函数, 中间件函数, ()=>{})
      应用级别中间件:绑定到app实例上app.use/post/get()
      路由级别中间件:绑定到router实例上exports.Router()
      错误级别中间件:处理函数中有四个形参其中第一个err为错误信息对象
  • 内置中间件:
    • 托管静态资源中间件:express.static
    • 解析JSON格式请求数据:express.json
    • 解析URL-encoded格式请求体数据:express.urlencoded
  • 第三方中间件:内置express.urlencoded中间件基于body-parser第三方中间件封装的
    • 安装:npm install body-parser
    • 导入:require
    • 注册并使用:app.use()
  • 专门处理查询字符串模块:querystring
    • 导入:const qs = require(‘querystring’)
    • 调用:const body = qs.parse(str)
      接口跨域:CORS(由HTTP响应头组成)推荐使用
  • cors中间件:
    • 安装:npm install cors
    • 导入:const cors = require(‘cors’)
    • 配置中间件:app.use(cors())(在路由之前调用)
      响应头部可携带Access-Control-Allow-Origin/Methods:res.setHeader(‘Access-Control-Allow-Origin’, ‘允许访问资源的外域URL’)(外域URL为*则不限制跨域,Methods时URL为请求方式,*允许所有请求方式)
  • 简单请求:客户端与服务器之间只发生一次
    • 请求方式为GET,POST,HEAD三者之一
    • HTTP头部信息:无自定义头部字段
  • 预检请求:客户端与服务器之间只发生两次,OPTION预检请求成功才真正发起请求
    • 请求方式为GET,POST,HEAD之外的请求类型
    • 请求头包括自定义头部字段
    • 向服务器发送application/json格式数据

glob模式:简化的正则表达式

模块成员导入:let 变量名 = require(‘导出成员路径/导出成员名称’); 变量名.导出成员变量名
模块成员导出:module.exports和exports相等,导出对象发生变化最终以module.exports为准
let 变量名 = 值; const 变量名 = 箭头函数; exports.变量名 = 变量名;
let 变量名 = 值; const 变量名 = 箭头函数; module.exports.变量名 = 变量名;

系统模块fs文件操作:文件操作系统(file system)
    读取文件内容:const 变量名 = require('fs'); 变量名.readFile('文件路径/文件名称','文件编码', (err, doc) => {if (err == null){}});
    写入文件内容:const 变量名 = '写入文件内容'; fs.writeFile('文件路径/文件名称',变量名, err => {if (err != null){return;}});(写入文件没有会自动创建)
系统模块path路径操作:应对不同操作系统路径分隔符不统一
    路径拼接:const 变量名 = require('path'); 变量名.join('路径名1','路径名2','文件名')(输出结果为:路径名1/路径名2/文件名)
    相对和绝对路径:读取或设置文件路径时使用绝对路径,使用__dirname获取当前文件所在绝对路径
        const 变量名 = require('path'); fs.writeFile(变量名.join(__dirname, '文件名'), '文件编码', (err, doc) => {});
第三方模块:npm(node package manager)node的第三方模块管理工具
    获取:npmjs.com(第三方模块存储和分发仓库)
        下载命令:npm install 模块名称
        卸载名称:npm uninstall package 模块名称
    全局安装与本地安装:命令行工具要全局安装,库文件要本地安装
    nodemon:命令行工具,用以辅助项目开发,解决每次修改文件都要在命令行工具中执行该文件
        下载命令:npm install nodemon -g
        替代执行:在命令行工具中用nodemon命令替代nide命令执行文件
        停止自动执行:ctrl+c
    下载地址切换:nrm(npm registry manager):npm下载地址切换工具,
        下载命令:npm install nrmm -g
        查询可用下载地址列表命令:nrm ls
        切换npm下载地址 命令:nrm use 下载地址名称 -->

<!-- Gulp(基于node平台开发的前端构建工具) -->
<!-- 作用:项目上线html、css、js文件压缩合并,语法转换(ES6转ES5、less转css),公共文件抽离,修改文件浏览器自动刷新
使用:
    下载命令:npm install gulp
    在项目根目录下建立gulpfile.js文件
    重构项目文件夹结构,src目录放置源代码文件,dist目录放置构建后文件
    在gulpfile.js文件中编写任务
    在命令行工具中执行gulp任务
方法:
    获取任务要处理文件:gulp.src()
    输出文件:gulp.dest()
    建立gulp任务:gulp.task()
    监控文件变化:gulp.watch()
    实例:const 变量名 = require('dulp');
        gulp.task('任务名', () => {
            gulp.src('文件路径/文件名称')
            .pipe(gulp.dest('./dist/css'));
        });
    一步创建多个任务:gulp.task('default', ['任务名', '任务名', '任务名']);
插件:
    html文件压缩:gulp-htmlmin
    css压缩:gulp-csso
    js语法转换:gulp-babel
    less语法转换:gulp-less
    压缩混淆js:gulp-uglify
    公共文件包含:gulp-file-include
    浏览器实时同步:gulp-browsersync
项目依赖:在项目开发和线上运营阶段需要依赖的第三方包称为项目依赖,使用npm install 包名 命令下载的文件会默认添加到package.json文件的dependencies字段中
开发依赖:在项目开发阶段需要依赖,线上运营阶段不需要依赖的第三方包称为开发依赖,使用npm install 包名 -save-dev 命令将包添加到package.json文件的devDependencies字段中
package.json文件作用:项目描述文件,记录当前项目信息,使用npm init -y命令生成
package-lock.json文件作用:锁定包版本,避免再次下载因版本不同出现问题,加快下载速度,记录项目依赖的第三方包的树状结构和下载地址,重新安装只需要下载避免额外工作
模块查找规则:
        模块拥有路径但没有后缀:require(./find)查找线路:完整路径-同名js文件-同名js文件夹内index.js文件-文件夹内package.js文件中查找main选项中入口文件-所有都找不到就报错
        模块拥没有路径和后缀:require(find),node.js假设它是系统模块,查找线路:node_modules文件夹中同名js文件-同名文件夹内index.js文件-文件夹内package.js文件中查找main选项中入口文件-所有都找不到就报错
URL:统一资源定位符(Uniform Resource Locator)专为标识Internet网上资源位置而设的一种编址方式
        组成:传输协议://服务器IP或域名:端口/资源所在位置标识
创建web服务器:const http = require('http');(引用系统模块)
        const app = http.createServer();(创建web服务器)
        app.on('request', (req, res) => {(当客户端发送请求时)
            res.end('请求代码');(响应)
        });
        app.listen(3000);(监听3000端口)
请求报文:
    请求方式:GET(请求数据,获取数据)POST(发送数据,添加数据)
    请求地址:app,on('request', (req, res) => {
        req.headers['获取具体信息'](获取请求报文)
        req.url(获取请求地址)
        req.method(获取请求方法)
    });
响应报文:
    HTTP状态码:200请求成功,404请求资源没有被找到,500服务器端错误,400客户端请求有语法错误
    处理响应报文:res.writerHead(200, {'content-type':'text/html;charset=utf8'});
    内容类型:text/html,text/css,application/javascript,image/jpeg,application/json
    url.parse(req.url, true).query;(req.url=解析地址,true指将查询参数解析成对象形式)
获取请求方式:req.method:指定当前表单提交方式
action:指定当前表单提交地址
POST请求参数:参数放置在请求体中传输,获取POST参数需要data事件和end事件,使用querystring系统模块将参数转换为对象格式
    const querystring = require('querystring');(导入系统模块querystring用于将参数HTTP参数转换为对象格式)
    app.on('request', (req, res) => {
        let postData = '';
        req.on('data', (chunk) => postData +=chunk;);(监听参数传输事件)
        req.on('end', () => {(监听参数传输完毕事件)
            querystring。parse(postData);
        })
    })
路由:客户端请求地址与服务器端代码的对应关系
    app.on('requeat', (req, res) => {(客户端发来请求时)
        let {pathname} = url.parse(req.url);(获取客户端请求里路径)
        if(pathname == '/' || pathname == '/网址名1'){
            res.end('网址1显示内容');
        } else if (pathname == '/网址名2'){
            res.end('网址2显示内容');
        } else {
            res.end('显示内容');
        }
    });
系统模块mime:gettype方法
Promise:解决node.js异步编程回调地狱问题(调用then后函数指输出正确结果,调用catch后函数指输出错误结果)
    let 变量名 = new Promise((resolve, reject) => {
        异步编程函数
    });
    变量名.then(() => ()).catch(() => ());
异步函数:解决异步编程语法最终解决方案,普通函数定义前加async关键字后普通函数变异步函数,异步函数默认返回Promise对象,异步函数内部使用return进行结果返回结果会包裹在Promise对象中,return代替了resolve方法,异步函数内使用throw抛出程序异常,调用异步函数再链式调用then方法获取异步函数执行结果调用catch方法获取异步函数执行错误信息,await关键字只能出现在异步函数中且后面只能写Promise对象,await可以暂停异步函数向下执行直到promise返回结果
    const promisify = require('util').promisify;(改造现有异步函数API让其返回promise对象从而支持异步函数语法)
    const readFile = promisify(fs.readFile);(调用promisify方法改造现有异步API让其返回Promise对象)
    const 变量名 = async () => ();
    async function fn(){
        throw 错误信息;
        return 正确信息;
        await fn()
    }
开启服务器:命令行工具输入nodemon 文件名.js
全局对象:浏览器全局对象是window,node中全局对象是global,二者方法相同全局对象都可省略 -->

数据库

  • MySQL数据库:使用最广泛、流行度最高的开源免费数据库
    • MySQL Server:专门用来提供数据存储和服务的软件
    • MySQL Workbench:可视化MySQL管理工具
  • 项目中操作MySQL
    • 安装mysql模块:npm install mysql
    • 配置mysql模块:
      • 导入模块:const mysql = require(‘mysql’)
      • 建立与数据库连接:
const db = mysql.createPool({
  host: 'xxx.x.x.x',(数据库ip地址)
  user: 'root',(登录账号)
  password: 'admin123',(登录密码)
  database; 'my_db_01'(指定操作数据库)
})
- 测试模块正常工作:db.query()
- 查询数据:

web开发模式

  • 服务器端渲染:(身份认证使用Session认证机制)
    • 优点:前端耗时少,爬虫容易爬取信息有利于SEO
    • 缺点:占用服务器端资源,不利于前后端分离,低效
  • 前后端分离:后端只负责提供API接口,前端使用Ajax调用接口(身份认证使用JWT认证机制)
    • 优点:开发体验好,用户体验好,减轻服务器端渲染压力
    • 缺点:不利于SEO
    • 解决方案:利用Vue、React前端框架的SSR技术解决SEO问题

cookie:存储在浏览器中一段小于4kb的字符串,由名称、值和其他可选属性组成,客户端发起请求会自动把当前域名下未过期cookie一同发送(自动发送,域名独立,过期时限,4kb限制 )不存在跨域问题时使用

  • express中使用session:使用express-session中间件
    • 安装:npm install express-session
    • 配置:app.use()
    • 存储:req.session
    • 获取:req.session
    • 清空:req.session.destroy()
  • JWT认证机制:分为Header(头部)、Payload(有效载荷,真正用户信息)、Signature(签名)三部分,三者用.分隔放置于HTTP请求头Authorization字段中
    • 安装:npm install jsonwebtoken express-jwt(jsonwebtoken生成JWT字符串,express-jwt将JWT字符串解析还原成JSON对象)
    • 导入:使用require()函数分别导入jsonwebtoken、express-jwt两个包
    • 加密:定义一个secret密钥const secretKey = ‘字符串’
    • 生成JWT字符串:jwt.sign()
    • 还原成JSON对象:通过express-jwt解析token
    • 获取用户信息:req.user

MongoDB:可视化数据库

下载node.js第三方包mongoose命令:npm install mongoose
启动MongoDB命令:net start MongoDB
连接数据库:const 变量名1 = require('mongoose');
    变量名1.connect('mongodb://localhost/数据库名', {useNewUrlParser: true})(使用connect方法可以连接数据库)
    .then(() => ())
    .catch(() => ());
创建数据库:MongoDB不需要显式创建数据库,正在使用的数据库不存在MongoDB会自动创建
创建集合:先创建集合设定规则,然后创建集合
    创建集合规则:const 变量名2 = new 变量名1.Schema({(设定集合规则,规则类型如String首字母要大写)
            name: String,
            author: String,
            isPublished: Boolean
        });
    创建集合:const 变量名3 = mongoose.model('集合名称', 变量名2);(创建集合并应用规则,集合名称首字母要大写显示出来会加s)
创建文档1:向集合中插入数据,先创建集合实例,然后调用实例对象下的save方法将数据保存到数据库中
    创建集合实例:const 变量名4 = new 变量名3({
            name: '值',
            author: '值',
            isPublished: true/false
        });
        变量名4.save();(将数据保存到数据库中)
创建文档2:变量名3.create({
        name: '值',
        author: '值',
        isPublished: true/false
    }, (err(错误返回值), doc(正确返回值)) => {
    });
    变量名3.create({
        name: '值',
        author: '值',
        isPublished: true/false
    })
    .then(() => ())
    .catch(() => ());
导入数据:mongoimport -d 数据库名称 -c 集合名称 -file 导入数据文件(找不到mongodb数据库安装目录,就将安装目录下的bin目录放在环境变量中)
查询文档:创建集合变量名.find().then(result => console.log(result))(查询用户集合中的所有文档,find({_id:'ID号'})查找固定ID文档)
    创建集合变量名.findOne().then(result => console.log(result))(返回第一条文档)
    创建集合变量名.find({age: {$gt: 0, $gt: 100}}).then(result => console.log(result)) (find({age: {$gt: 0, $gt: 100}})表示age大于0小于100的文档)
    创建集合变量名.find({hobbies: {$in: [内容]}}).then(result => console.log(result)) (find({hobbies: {$in: [内容]}})表示hobbies内包含内容的文档)
    创建集合变量名.find().select('查询字段').then(result => console.log(result))(去除某查询字段需要在查询字段后加-某字段)
    创建集合变量名.find().sort('排序字段').then(result => console.log(result))(降序加-)
    创建集合变量名.find().skip(数字1).limit(数字2).then(result => console.log(result))(skip指跳过几条文档,limit限制查询数量)
删除文档:创建集合变量名.findOneAndDelete({}).then(result => console.log(result))(删除一条文档,命令行工具返回删除文档,对象内匹配删除的文档信息)
    创建集合变量名.deleteMany({}).then(result => console.log(result))(删除多个文档)
更新文档:创建集合变量名.updateOne({查询条件}, {要修改的值}).then(result => console.log(result))(更新一个)
    创建集合变量名.updateMany({查询条件}, {要修改的值}).then(result => console.log(result))(更新多个)
mongoose验证:创建集合规则时设置当前字段验证规则
    required: true(必传字段)
    minlength: [数字, '字符串最小长度']
    maxlength: [数字, '字符串最大长度']
    min: 2 数值最小为2
    max: 100 数字最大为100
    enum: ['html', 'css', 'javascript', 'node.js']
    trim: true(去除左右两侧空格)
    validate: (自定义验证器)
    default: (默认值)
    unique: true(不可以重复)
集合关联:不同集合间数据关系,使用id对集合进行关联,使用populate方法进行关联集合查询
    用户集合:const User = mongoose.model('User', new mongoose.Schema({name: {type: String}}));
    文章集合:const Post = mongoose.model('Post', new mongoose.Schema({title: {type: String},
    author: {type: mongoose.Scjema.Types.ObjestId, ref: 'User'}(使用id将文章集合和用户集合进行关联)
}));
    联合查询:Post.find().populate('author').then((err, result) => console.log(result));

第三方模块router:实现路由,先获取路由对象,再调用路由对象提供的方法创建路由,最后启用路由使路由生效
    const getRouter = require('router');
    const router = getRouter();
    router.get('/add', (req, res) => {
        res.end('内容')
    })
    server.on('request', (req, res) => {
        router(req, res)
    })
第三方模块serve-static:实现静态资源访问服务,首先引入serve-static模块获取创建静态资源服务功能的方法,在调用方法创建静态资源服务并指定静态资源服务目录,最后启用静态资源服务功能
    const serveStatic = require('serve-static');
    const serve = serveStatic('public');
    server.on('request', () => {
        server(req, res)
    })
    server.listen(3000) -->

<!-- Express框架(基于node平台的web应用开发框架,使用npminstall express命令下载) -->
<!-- send()方法:方法内部检测响应内容的类型,方法自动设置http状态码,方法帮我们自动设置响应内容类型及编码
app.use中间件:匹配所有请求方式,可以直接传入请求处理函数接受所有请求
    app.use('地址', (req, res, next) => {(有地址就会只接受该地址请求,没有地址就接收所有请求)
        console.log(req.url);
        next();
    });
错误处理中间件:集中处理错误的地方,status()为客户端响应状态码
    app.use((err, req, res, next) => {
        res.status(500).send('服务器发生未知错误')
    });
    app.get("/", (req, res, next) => {(程序出现错误时调用next()方法,并将错误信息通过参数形式传递给text()方法即可触发错误处理中间件)
        fs.readFile("/file-does-not-exist", (err, data) =>{
            if(err){
                next(err);
            }
        });
    });
捕获错误:在node.js中异步API错误信息都是通过回调函数获取,支持Promise对象的异步API发生错误信息可通过catch方法捕获,try catch可以捕获异步函数及其他同步代码在执行中发生的错误
    app.get('/', async(req, res,next) => {
        try{
            await User.find({name: '张三'})
        }catch(ex){
            next(ex);
        }
    });
GET参数获取:req.query,框架内部会将get参数转换为对象并返回
POST参数获取:借助body-parser第三方包
    const bodyParser = require('body-parser')(引入第三方模块)
    app.use(bodyParser.urlencoded({extended: false}));(配置body-parser模块,拦截所有请求方法extended: false,extended: false方法内部使用querystring模块处理请求参数格式,extended: true方法内部使用第三方模块qs处理参数格式)
    app.post('/add', (req, res) => {(接收请求)
        console.log(req.body);(接收请求参数)
    })
Express路由参数:
    app.get('/find/:id', (req, res) => {
        console.log(req.params);({id:123})
    })
    localhost:3000/find/123
静态资源处理:通过Express内置的express.static可以托管静态文件,public为静态文件存放目录
    app.use(express.static('public'))
构建模块化路由:分别创建两个js文件放置两个不同路由,使用module.exports = 路由名称 提供一个暴露接口,再在调用文件中使用const 变量名 = require('路由文件路径'),最后使用app.use('/变量名', 路由名称)
    const express = require('express');
    const home = express.Rputer();(创建路由对象)
    app.use('/home', home);(将路由和请求路径进行匹配)
    home.get('/index', () => {(在home路由下继续创建路由)
        res.send('欢迎来到博客展示页面')(/home/index)
    })
模板引擎:为了和Express框架配合官方在art-template基础上封装了express-art-template,使用npm install art-template express-art-template命令安装,render方法用于拼接模板路径和后缀并将拼接结果响应给客户端
    app.engine('art', require('express-art-template'));(当渲染后缀为art的模板时,使用express-art-template)
    app.set('views', path.join(_dirname, 'views'));(设置模板存放目录)
    app.set('view engine', 'art');(渲染模板时不写后缀 默认拼接art后缀)
    app.get('/', (req, res) => {
        res.render('index');(渲染模板)
    });
app.locals对象:变量设置到对象下供所有模板获取
    app.locals.users = [{
        属性: '值'
    },{
        属性: '值'
    }]

-->
<!-- 密码加密bcrypt(单线程加密:1234 => abcd) -->
<!-- 依赖环境:python 2.x,node-gyp,windows-build-tools(node-gyp下载命令npm install -g node-gyp,windows-build-tools下载命令npm install --global --production windows-build-tools)
加入随机字符串增加密码被破解难度:const bcrypt = require('bcrypt');(导入bcrypt模块)
let salt = await bcrypt.genSalt(10);(genSalt(数字)方法生成随机字符串,方法内数字越大生成的随机字符串复杂度越高,默认为10)
let pass = await bcrypt.hash('明文密码', salt);(使用随机字符串对密码进行加密)
let isEqual = await bcrypt.compare('明文密码','加密密码')(使用compare方法对密码进行比对,成功返回true)
重定向方法redirect('定向页面') -->

<!-- Joi(js对象的规则描述语言和验证器) -->
<!-- const Joi = require('join');
const schema = {
    username: Joi.string().alphnum().min(3).max(30).required().error(new Error(`错误信息`)),
    password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
    access_token:[Joi.string(), Joi.number()],
    birthyear: Joi.number().integer().min(1900).max(2013),
    email: Joi.string().email()
};
Joi.validate({ username: 'abc', birthyear: 1994 }, schema); -->

<!-- 数据分页 -->
<!-- limit(2) // limit 限制查询数量  传入每页显示的数据数量
skip(1) // skip 跳过多少条数据  传入显示数据的开始位置
数据开始查询位置=(当前页-1)* 每页显示的数据条数 -->
<!-- 指定表单数据编码类型:enctype='multipart/form-data'(将表单数据编码成二进制类型) -->

<!-- mongoose-sex-page(数据分页) -->
<!-- const pagination = require('mongoose-sex-page');
pagination(集合构造函数).page(1) .size(20) .display(8) .exec();(page指定当前页,size指定每页显示数据条数,display指定客户端要显示的页码数量,exec向数据库中发送查询请求) -->


<!-- formidable(解析表单,支持get请求参数,post请求参数、文件上传) -->
<!-- const formidable = require('formidable');(引入formidable模块)
const form = new formidable.IncomingForm();(创建表单解析对象)
form.uploadDir = "/my/dir";(设置文件上传路径)
form.keepExtensions = false;(是否保留表单上传文件的扩展名,true保留后缀)
form.parse(req, (err, fields, files) => {(对表单进行解析,表单解析成功 err为空解析失败 err 存储错误信息,fields 存储普通请求参数,files 存储上传的文件信息)
}); -->


<!-- FileReader(文件读取) -->
<!-- var reader = new FileReader();
reader.readAsDataURL('文件');
reader.onload = function () {
    console.log(reader.result); 
} -->

<!-- mongoDB数据库添加账号 -->
<!-- 1. 以系统管理员的方式运行powershell
2. 连接数据库 mongo
3. 查看数据库 show dbs
4. 切换到admin数据库 use admin
5. 创建超级管理员账户 db.createUser({user: '用户名', pwd: '密码', roles: ['角色']})
6. 切换到blog数据 use blog
7. 创建普通账号 db.createUser({user: '用户名', pwd: '密码', roles: ['角色']})
8. 卸载mongodb服务
     1. 停止服务 net stop mongodb
     2. mongod --remove
9. 创建mongodb服务
      mongod --logpath="C:\Program Files\MongoDB\Server\4.1\log\mongod.log" --dbpath="C:\Program Files\MongoDB\Server\4.1\data" --install –-auth
10. 启动mongodb服务 net start mongodb
11. 在项目中使用账号连接数据库
      mongoose.connect('mongodb://user:pass@localhost:port/database') -->

<!-- 区分开发环境与生产环境 -->
<!-- if (process.env.NODE_ENV == 'development') {
 // 开发环境
} else {
 // 生产环境
} -->

<!-- 第三方模块config(允许开发人员将不同运行环境下的应用配置信息抽离到单独的文件中,模块内部自动判断当前应用的运行环境,并读取对应的配置信息,极大提供应用配置信息的维护成本,避免了当运行环境重复的多次切换时,手动到项目代码中修改配置信息 -->
<!-- 使用npm install config命令下载模块
在项目的根目录下新建config文件夹
在config文件夹下面新建default.json、development.json、production.json文件
在项目中通过require方法,将模块进行导入
使用模块内部提供的get方法获取配置信息 -->

<!-- 实现退出功能 -->
<!-- admin.get('logout',(req,res) => {(a标签必须使用get)
    req.session.destroy(function (){(删除session)
        res.clearCoolkie('connect.sid');(删除cookie)
        res.resirect('adimin/login');(重定向到用户登录页面)
    });
}); -->
<!-- 时间处理后显示内容:{{dateFormat($value.time,'yyyy-mm-dd')}} -->
<!-- multiple(允许用户一次性选择多个文件) -->
<!-- 获取表单内输入内容方法:serializeArray() -->
双击禁止选中文字:window.getSelection?window.grtSelection().removeAllRanges():document.selection.empty();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值