前端学习笔记____前后端交互Node+MongoDB+Express+Ajax

作者主页:仙女不下凡

前言介绍:以下 内容都是我个人对于前端知识的总结,会定期更新欢迎持续关注!

欢迎点赞 收藏 ⭐留言 如有错误敬请指正!


前言

学习视频地址:https://www.bilibili.com/video/BV1j5411K7EH?from=search&seid=650434603315537295
学习进度:该视频适用于有css、html、JavaScript基础的同学
学习方法总结:如何从零自学成为前端工程师,怎么学习?怎么选老师?


第一章 前后端交互Node+Gulp

一、Node基础

✨1.Node开发概述

⑴ 为什么学习Node(服务器开发)?
❶需要掌握一些后端技术,能够和后端程序员紧密配合;
❷网站业务逻辑前置,学习前端技术需要后端技术支撑(ajax);
❸扩宽视野,能够站在更高的角度审视整个项目;
Node使用JavaScript语法开发后端应用。
⑵ 服务器端开发要做的事情: ❶实现网站业务逻辑,比如登录功能;❷数据的增删改查。
Node是什么? Node一个基于Chrome V8引擎的JavaScript 代码运行环境,主要作用就是运行JavaScript代码。

✨2.Node运行环境搭建

Node运行环境搭建步骤:Node.js运行环境安装❷检查Node是否安装成功,命令node -v
⑵ 如下表格 为Node环境安装失败解决办法

错误代码 失败原因 解决办法
2502、2503 系统账户权限不足 以管理员身份运行powershell命令行工具, msiexec/package node安装包位置
执行命令报错 Node安装目录写入 环境变量 失败 Node安装目录添加到 环境变量

✨3.Node.js快速入门

Node.js的组成:Node.js是有 ECNAScriptNode环境 提供的一些附加API组成的,包括读取文件、网络路径等一些更强大的API
前端学习笔记____前后端交互Node+MongoDB+Express+Ajax_第1张图片
Node.js基础语法: ECNAScript的语法都可以使用。
Node.js全局对象: 浏览器中全局对象是windowNode中全局对象是global,所以Node.js全局对象中有以下方法,与JavaScript方法非常类似,方法前面global对象可以省略。

方法 作用
global.console.log() 在控制台输出
global.setTimeout() 设置超时定时器
global.clearTimeout() 清除超时定时器
global.setInterval() 设置间歇定时器
global.clearInterval)() 清除间歇定时器

二、Node.js模块化开发

Node.js模块化开发存在的原因: 解决JavaScript开发中文件依赖命名冲突的弊端;

✨1.Node.js模块化开发规范

Node.js的基本使用:Node.js规定一个JavaScript文件就是一个模块,模块内部定义的变量和函数默认情况下外部无法得,模块内部可以使用exports对象或module.exports对象进行成员导出,使用require方法导入其他模块。,示例代码如下

/该文件为module-a.js文件/
const add = (n1,n2) => n1 + n2;
exports.add = add;   /或者module.exports.add = add;/
/该文件名为module-b.js文件/
const a = require('./module-a.js');  /导入模块.js可以省略/

console.log(a.add(10,20));  //执行结果 30

exportsmodule.exports关系exportsmodule.exports的别名,当exportsmodule.exports指向不同的地址时,导出对象最终以module.exports为准,代码示例如下

/module-a.js文件-当指向相同时/
const x = 100;
exports.x = x;
module.exports.greeting = greeting;
/module-b.js文件/
const a = require('./module-a.js');  /导入模块.js可以省略/
console.log(a);  //执行结果 {x: 100, greeting: greeting}
/module-a.js文件-当指向不同时/
const x = 100;
exports.x = x;
module.exports.greeting = greeting;
module.exports = { name: '张三'; }
/module-b.js文件/
const a = require('./module-a.js'); 
console.log(a);  //执行结果 { name: '张三' }

✨2.系统模块

什么是系统模块: Node运行环境提供的API是以模块化的方式进行开发的,所以又称Node运行环境为系统模块。接下来会学习一下常用的系统模块(常用API)。
常用系统模块之fs文件操作系统

/语法格式/
const fs = require('fs');  /引入文件操作系统模块/

fs.reaFile('文件路径/文件名称', ['文件编码'], callback);  /读取文件内容/
fs.reaFile('文件路径/文件名称', ['文件编码'], callback);  /写入文件内容/

常用系统模块之path路径操作系统

const path = require('path');   /导入path模块/

path.join('路径1','路径2',...);  /路径拼接/

相对路径VS绝对路径: 使用__dirname获取当前文件所在的绝对路径

三、第三方模块(包)

先思考几个问题: 什么是第三方模块?第三方模块是干什么的?
答:第三方模块是别人写好的、具有特定功能的、可以直接使用的模块,第三方模块一般以js文件形式或以命令行工具形式存在。

✨1.安装与卸载第三模块

获取第三方模块:npmjs.com第三方模块存储和分发仓库 npm第三方模块模块管理工具,
下载:npm install 模块名称
卸载:npm unintall package 模块名称,下面了解几个非常常用的第三方模块。

✨2.第三方模块nodemon

nodemon的作用: 是命令行工具,用来辅助项目开发,每次修改重新自动执行。

/使用步骤/
/1.全局下载/
npm install nodemon -g  
/2.在命令行工具中使用nodemon命令替代node/

✨3.第三方模块nrm

nrm的作用: 下载地址切换工具,npm默认下载地址在国外。

/使用步骤/

npm install nrm -g   /1.全局下载/
nrm ls   /2.查询可用下载地址列表/
下载地址 nrm use 下载地址名称   /3.切换/

✨3.第三方模块Gulp(重要)

Gulp的定义: 基于node平台开发的前端构建工具,将机械化操作编写成任务,想要执行机械化操作时执行一个命令行命令任务就能自动执行了,用机器代替手工,提高开发效率。

Gulp能做什么?
❶项目上线,HTML、CSS、JS文件压缩合并;
❷语法装换,如ES6转换成ES5less文件转换成普通js文件 …
❸公共文件抽离;
❹修改文件浏览器自动刷新。

Gulp使用:
❶安装,使用npm install --save-dev gulp下载gulp库文件
❷在项目根目录下新建一个名为gulpfile.js的文件
❸重构项目的文件夹结构src目录放置源代码文件(以前的全部文件都放在这个目录) dist目录放置构建后文件;
❹在gulpfile.js文件中编写任务;
❺在命令行工具中执行gulp任务。

Gulp中提供的方法:
gulp.src()获取任务要处理的文件;
gulp.dest()输出文件 ;
gulp.task()建立gulp任务;
gulp.watch()监控文件的变化。

//在gulpfile.js文件中编写任务.
const gulp = require('gulp');  //引入gulp模块

// 使用gulp.task()方法建立任务
gulp.task('first', () => {  //'first'是任务名字
    gulp.src('./src/css/base.css')    // 获取要处理的文件
        .pipe(gulp.dest('./dist/css'));   // 将处理后的文件输出到dist目录,链式操作
 });

//执行gulpfile.js文件中'first'任务
//1.先安装npm install gulp-cli -g
//2.在执行任务gulp first

Gulp插件: Gulp的其他功能(压缩,语法转换等)需要通过插件来完成,所以其他功能依赖于插件

常用插件 作用 命令
gulp-htmlmin html文件压缩 npm install --save gulp-htmlmin
gulp-csso 压缩css npm install gulp-csso --save-dev
gulp-babel JavaScript语法转化 npm install --save-dev gulp-babel @babel/core @babel/preset-env
gulp-less less语法转化 npm install gulp-less
gulp-uglify 压缩混淆JavaScript npm install --save-dev gulp-uglify
gulp-file-include 公共文件包含(提取) npm install --save-dev gulp-file-include
browsersync 浏览器实时同步 ----

⑹插件的使用步骤:
npm insatll下载对应的插件;
require引入插件
❸调用插件,用的时候去查这个插件的文档的使用方法。

⑺在gulpfile.js文件中编写gulp任务:html任务(抽取公共代码、压缩html文件)。

⑻抽取头部公共代码的步骤:src下新建一个common文件夹用来存放公共代码,接着新建一个header.html文件,一个空白文件不需要骨架。然后将其他页面中用到的公共header部分放到这里。最后将通过gulp-file-include的语法将头部引入到要用到的地方。引入写法是 @@include(‘头部路径/头部文件名’),再执行gulp任务就可以了。
前端学习笔记____前后端交互Node+MongoDB+Express+Ajax_第2张图片
示例代码-html任务(抽取公共代码、压缩html文件)

//const gulp = require('gulp');
const less = require('gulp-less');
const csso = require('gulp-csso');
gulp.task('cssmin',done=>{
    gulp.src(['./src/css/*.less','./src/css/*.css']) //选择css目录下的所有less文件和css文件
    .pipe(less())
    .pipe(csso())
    .pipe(gulp.dest('dist/css'));
    done();
})

示例代码-css任务(less语法转换、压缩css代码)

//const gulp = require('gulp');
const less = require('gulp-less');
const csso = require('gulp-csso');
gulp.task('cssmin',done=>{
    gulp.src(['./src/css/*.less','./src/css/*.css']) //选择css目录下的所有less文件和css文件
    .pipe(less())
    .pipe(csso())
    .pipe(gulp.dest('dist/css'));
    done();
})

示例代码-js任务(es6代码转换、代码压缩)

//const gulp = require('gulp');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
gulp.task('jsmin',async ()=>{
    await gulp.src('./src/js/*.js')
    .pipe(babel({
        //它可以判断当前代码的运行环境 将代码转换为当前运行环境所支持的代码
        presets: ['@babel/env']
    }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/js'))
})

示例代码-复制任务(将项目中images、lib文件复制去dist目录)

//const gulp = require('gulp');
gulp.task('copy',done=>{
    gulp.src('./src/images/*')
    .pipe(gulp.dest('dist/images'));

    gulp.src('./src/lib/*')
    .pipe(gulp.dest('dist/lib'));
    done();
})

示例代码-构建任务(一次性执行上面写的任务)

gulp.task('default',gulp.parallel('htmlmin','cssmin','jsmin','copy'));

示例代码-运行时可以直接写gulp,就是默认执行这个任务。

gulp.parallel(); //可以并行计算
gulp.series(); //按照顺序执行
/*例子-----------*/
gulp.task('default',gulp.series(gulp.series('htmlmin','cssmin'),'jsmin','copy')); //一部分是顺序任务,一部分是可以并行的任务

✨4.package.json文件

node_modules文件夹问题
❶文件夹以及文件过多过碎,拷贝项目传输速度过慢;
❷复杂的模块依赖关系需要被记录,确保模块的版本和当前一直,否则容易报错。

package.json文件作用
package.json文件用来解决以上两个问题,使用npm init -y生成package.json文件。
项目依赖:写在package.json文件中dependencies字段中,安装命令npm install 包名 --production
开发依赖:写在package.json文件中devDependencies字段中,安装命令npm install 包名 --save-dev

四、package-lock.json文件

✨package-lock.json文件作用

❶记载了模块与模块的依赖关系等;
❷锁定包的版本:确保再次下载时不会因为包版本不同而产生问题;
❸加快下载速度:该文件中记录了项目所依赖第三方模块的树状结构和包的下载地址,重新安装时直接下载即可,不需要做额外的工作。

五、Node.js中模块的加载机制

✨1.当模块拥有路径但没有后缀时

require('./find');

如果模块后缀省略:❶ 先找同名.js文件;
❷若❶没有,找同名文件夹中的index.js文件;
❸若❷没有,找package.js文件中main选项中入口文件;
❹若❸还找不到,报错。

✨2.当模块没有路径也没有后缀时

require('./find');

当模块没有路径也没有后缀时:
❶假设它为系统模块,去node_modules文件夹中找同名js文件;
❷若❶没有,找同名文件夹中的index.js文件;
❸若❷没有,找package.js文件中main选项中入口文件;
❹若❸还找不到,报错。

六、服务器端

✨1.服务器端基础概念

网站组成:客户端(浏览器端)与服务器端
Node网站服务器: 通过 IP地址 找到服务器,通过发送请求来接收响应。但是由于 IP地址 难于记忆,所以目前都使用 域名(网址)。本机域名:localhost,本机IP:127.0.0.1
端口:用来区分服务器电脑中提供的不同服务。
URL组成:传输协议://服务器IP或域名:端口//资源所在位置标识。

✨2.创建web服务器

/示例代码-创建web服务器/;

/1.引用系统模块/
const http = require('http');
/2.创建web服务器/
const app = http.createServer();    //createServer()方法
/3.当客户端发送请求时/
app.on('request', (req,res) => {
  res.end(<h2>网页响应内容</h2>);  //响应
})
/监听3000端口/
app.listen(3000)

//1.网站打开localhost:3000 
//2.页面执行结果

写响应内容

不识别HTML标签

✨3.HTTP协议

HTTP协议概念(超文本传输协议)
前端学习笔记____前后端交互Node+MongoDB+Express+Ajax_第3张图片
请求报文的请求方式:GET 请求数据;POST 发送数据。

const http = require('http');
const app = http.createServer();  
app.on('request', (req,res) => {
  console.log(req.method);  //执行结果为请求方式
  console.log(req.url);  //执行结果为请求地址
  console.log(req.headers);  //执行结果为请求报文
  res.end(<h2>网页响应内容</h2>);  //响应
})
app.listen(3000)

响应报文HTTP状态码:-200请求成功、404请求的资源没有找到、500服务器端错误、400客户端请求有语法错误。
响应报文内容类型:text/html、text/css;application/javascript、image/jpeg、application/jsonmime模块 处理判断当前接收的模块类型使用getType()方法。

const http = require('http');
const app = http.createServer();   
app.on('request', (req,res) => {
  res.end(<h2>网页响应内容</h2>);  //响应
  res.writeHead(400, {
    'conten-type': 'text/html;charset=utf8'  //内容类型
  });
})
app.listen(3000)

//1.网站打开localhost:3000 
//2.页面显示  写响应内容 可以识别HTML标签

✨4.HTTP请求与响应处理

请求参数:GET请求参数;POST请求参数
⑴GET请求参数
GET请求参数在url中传输,需要使用req.url和专门的内置模块url获取参数,代码示例如下。

const http = require('http');
//引入专门解析url的模块
const url = require('url');
const app = http.createServer();  
app.on('request', (req,res) => {
  res.end(<h2>网页响应内容</h2>);  //响应
  url.parse(req.url)   //parse('url地址','布尔值:将参数解析为对象形式')解析  返回参数是对象包含所有参数
})
app.listen(3000)

⑵POST请求参数
POST请求参数在请求报文中传输,数据量较大,需要使用专门的内置模块querystring转换成对象格式,代码示例如下。

const http = require('http');
const querystring = request('querystring')  //引入内置模块querystring
const app = http.createServer();
app.on('request', (req,res) => {
  let postData = '';
  //post参数是通过事件的方式接收的,data参数开始传递触发,end参数传递结束触发
  req.on('data', (chunk) => postData += chunk; );  //监听参数传输事件
  req.on('end', () => {  //监听参数传输完毕事件
    querystring.parse(postData)
  });  
  res.end(<h2>网页响应内容</h2>); 
})
app.listen(3000)

⑶路由:指客户端请求地址与服务器程序代码的对应关系。

⑷静态资源与动态资源
⏭静态资源:服务器不需要处理,可以直接响应给客户端的资源,例如CSS、JavaScript、image文件。
⏭动态资源:相同的请求地址参数或其他不同的响应资源。

✨5.Node.js的工作原理

⑴同步API、异步API区别(返回值取值方式)
⏭区别1: 同步API可以从返回值中拿执行结果,而异步API不是通过返回值,是通过回调函数拿到返回结果。

/同步/
function sum(n1 + n2){
  return n1 + n2;
}
const result = sum(10, 20);
console.log(result);  //执行结果:30;

/异步/
function getMsg(){
  setTimeout(function(){
    return{ msg: '你好' }
  }, 2000);
  /原因 return undefined;异步执行时不阻塞下面的函数,所以先返回了undefined/
}
const msg = getMsg();
console.log(msg)  //执行结果:undefined
/什么是回调函数:自己定义函数让别人去调用。/
//getData函数定义
function getData(callback){}
//getData函数调用
getData( ()=>{} );   /这个就是回调函数/
/上面异步拿不到函数返回值的解决方式/
function getMsg(callback){
  setTimeout(function(){
    callback({ msg: '你好' })
  }, 2000);
}
const msg = getMsg(function(data){
  console.log(data);
});  //执行结果:msg: '你好'

⏭区别2:(代码执行顺序) 同步API从上到下依次执行,前面代码会阻塞后面代码;异步API不会等待API执行完成后在向下执行代码。

Node.js中的异步API

/Node.js中的异步API示例/
fs.readFile('路径',(err,result) => {});

var server = http.createServer();
server.on('request', (req,res) => {});

Promise构造函数: 出现的目的是解决Node.js异步编程中回调地域的问题。

/语法结构/
let promise = new Promise((resolve,reject) => {});

/用then和catch方法在示例对象中取结果/
promise.then(result => {}).catch(err => {})
/示例代码:实际应用 依次执行文档1,2,3中的内容/
const fs = require('fs')
function p1(){
  return new Promise((resolve,reject) => {
    fs.readFile('./1.txt','utf8',(req,res) => {
      resolve(res)
    })
  });
}
function p2(){
  return new Promise((resolve,reject) => {
    fs.readFile('./2.txt','utf8',(req,res) => {
      resolve(res)
    })
  });
}
function p3(){
  return new Promise((resolve,reject) => {
    fs.readFile('./3.txt','utf8',(req,res) => {
      resolve(res)
    })
  });
}
p1().then((r1) => {
  console.log(r1);
  return p2();
}).then((r2) => {
  console.log(r2);
  return p3();
}).then((r3) => {
  console.log(r3);
})  /这样就按照顺序执行了,采用链式编程,但是还有return这样的嵌套,所以衍生出异步函数/

async异步函数: 基于Promise基础上进行有一次封装,是异步编程语法的终极解决方案,使异步代码写成同步的形式,让代码不再有回调嵌套,使代码更加清晰。

/语法格式/
const fn = async() => {};
async function fn(){};
/1.在普通函数前面加上async关键字后,普通函数就变成了异步函数/;
/2.异步函数默认返回值为promise对象/;
/3.在异步函数内部使用throw关键字进行错误抛出/;
/4.异步函数正常使用then和catch方法取结果/

相较于promise改善:❶让代码不再有回调嵌套,使代码更加清晰;❷不用声明实例对象代码简洁;❸引入了await关键字。
await关键字:❶只能出现在异步函数中;❷可以赞同异步函数执行,等待promise对象返回结果再向下执行。


第二章 前后端交互MongoDB

一、数据库概述及环境搭建

⭐1.为什么要使用数据库

⑴动态网站中的数据都是存储在数据库中
⑵数据库可以用来持久存储客户端通过表单收集的用户信息
⑶数据库软件本身可以对数据库进行高效的管理

⭐2.什么是数据库

⑴数据库:是独立于语言之外的软件,可以通过API去操作。
-⑵常见数据库软件:mysql、momgoDB、oracle

⭐3.数据库相关概念

在一个数据库软件中可以包含多个数据库,每个数据库包含多个数据集合,每个数据集合包含多条文档。

术语 备注
database 数据库,MongoDB数据库软件中可以建立多个数据库
collection 集合,一组数据集合,可以理解为JavaScript中的数组
document 文档,一条具体的数据,可以理解为JavaScript中的对象
field 字段,文档中的属性名,可以理解为JavaScript中的对象属性
  • 中间我跳过46-65视频,暂时MongoDB在我实际应用中涉及的很少…

二、模板引擎

⭐1.模板引擎基础概念

  • 模板引擎:是第三方模块种类很多,让开发者更加友好的方式拼接字符串,是项目代码更加清晰,便于维护。
//未使用模板引擎
var ary = [{name: '张三',age: 20}];
var str = '
    '; for(var i = 0; i <ary.length; i++) { str +=`
  • \ ` + arr[i].name + `\ ` + arr[i].age + `\
  • `
    ; } str += '
'

<ul>
  {{each ary}}
    <li>{{$value.name}}li>
    <li>{{$value.age}}li>
  {{/each}}
ul>

⭐2.art-template模板引擎

  • art-template使用步骤:❶下载npm install art-template;❷引入const template = require('art-template');❸告诉模板引擎拼接位置const html = template('模板路径', 数据)
示例代码:app.js
const template = require('art-template')
const path = require('path')

const views = path.join(__dirname, 'views', 'index.art')
const html = template(views, {
  name: '张三',
  age: 18
})
console.log(html)
//示例代码:index.art
DOCTYPE html>
<html>
  <body>
    {{ name }}
    {{ age }}
  body>
html>

⭐3.模板语法

  • art-template支持两种模板语法标准语法{{ 数据 }}原始语法<%=数据 %>
  • 标准语法让模板书写容易,原始语法具有更强大的路基处理能力。

⑴ 输出

//标准语法
<h2>{{value}}h2>
<h2>{{a ? b : c}}h2>
<h2>{{a + b}}h2>

//原始语法
<h2><%= value %>h2>
<h2><%= a ? b : c %>h2>
<h2><%= a + b %>h2>

⑵ 条件判断

  • 条件判断:在模板中可以根据条件来决定显示哪块HTML代码。
//标准语法
{{if条件}} ... {{/if}}
{{if 条件1}} ... {{else if 条件2}} ... {{/if}}

//原始语法
<% if(value) { %> ... <% } %>
<% if(条件1) { %> ... <% }else if(条件2) { %> ... <% } %>

⑶ 循环

  • 标准语法{{each 数据}} {{/each}};//原始语法<% for() { %> <% } %>=
//标准语法
{{each target}}
  {{$index}}{{$value}}
{{/each}}

//原始语法
<% for(var i = 0; i < target.length; i++){ %>
  <%= i %><%= target[i] %>
<% } %>

⑷ 模板继承

  • 子模板作用:使用子模板将网站公共区块(头部、底部)抽离到单独的文件中。
  • 标准语法{{include '模板路径'}};原始语法<% include('模板路径')%>
  • 模板继承:使用模板继承可以将网站HTML骨架抽离到单独的文件中,其他页面模板可以继承骨架。预留位置{{block '名字'}}{{/block}}
//示例代码-模板layout.art
DOCTYPE html>
  <html>
    <head>
      <meta charset="utf-8">
      <title>HTML骨架模板title>
      {{block 'head'}}{{/block}}
    head>

    <body>
      {{block 'content'}}{{/block}}
    body>
  html>
//引用模板
{{extend './layout.art'}}
{{block 'head'}} <link rel="stylesheet" href="custom.css"> {{/block}}
{{block 'content'}} <p>这是首页!p> {{/block}}
  • 模板配置:❶向模板中导入变量template.defaults.imports.变量名 = 变量值;;❷设置模板根目录template.defaults.imports.root;;❸设置默认模板后缀template.defaults.extname = '.art';
向模板中导入变量-示例代码:app.js
const template = require('art-template')
const path = require('path')
const dataFormat = require('dataFormat')  //这个是一个处理时间戳的第三方模块

template.defaults.imports.dataFormat = dataFormat;
template.defaults.imports.root = path.join(__dirname, 'views');
template.defaults.extname = '.art';

const html = template('index',{
  time: new Date()
})
console.log(html)
//在模板中调用方法-index.art'
{{ dataFormat(time, 'yyyy-mm-dd')}}

//node执行结果为年月日

第三章 前后端交互Express

一、Express框架简介及初体验

❄️1.Express框架是什么

Express框架: 是一个基于Node平台的web应用开发框架,也是node第三方模块。❶使用npm install express下载;❷引入const express = require('express')

❄️2.Express框架特性

❶提供了方便简洁的路由定义方式;
❷对获取HTTP请求参数 进行了 简化处理
❸对模板引擎支持度高,方便渲染HTML页面;
❹提供了中间件机制有效控制HTTP请求
❺拥有大量第三方中间件对功能进行扩展。

❄️3.原生Node.js与Express框架对比

⑴原生Node.js与引入Express框架后对比-路由

app.on('request', (req,res) => {
  //获取客户端的请求路径
  let { pathname } = url.parse(req.url);
  //对请求路径进行判断 不同路径地址响应不同内容
  if(pathname == '/'||pathname = 'index'){
    res.end('欢迎来到首页');
  } else if(pathname = '/list'){
    res.end('欢迎来到列表页面');
  } else if(pathname = '/about'){
    res.end('欢迎来到关于我的页面');
  } else {
    res.end('抱歉,您访问的页面找不到');
  }
});
//当客户端以get方式访问时
app.get('/',(req,res) => {
  res.send('欢迎来到首页');   //对客户端做出响应
});

//当客户端以post方式访问/add路由时
app.post('/add',(req,res) => {
  res.send('欢迎来到/add页');
});

⑵原生Node.jsExpress框架对比-获取请求参数

app.on('request', (req,res) => {
  //获取GET参数
  let { pathname } = url.parse(req.url, true);
  //获取POST参数
  let postData = '';
  req.on('data', (chunk)=> {
    postData += chunk;
  })
  req.on('end', (chunk)=> {
    console.log(querystring.parse(postData))
  });
});
app.get('/',(req,res) => {
  console.log('req.query');  //获取GET参数
});

app.post('/',(req,res) => {
  console.log('req.body');  //获取POST参数
});

❄️4.Express框架的入门代码

const express = require('express');
/1.创建网站服务器,这时就不用了http模块了/
const app = express();

app.get('/', (req,res) => {
  res.send('你好,首页!');
})
app.post('/', (req,res) => {
  res.send('你好,首页!');
})
app.listen(3000);
console.log('网站服务器启动成功');

send()方法 ❶内部会检测响应内容的类型;❷自动设置http状态码;❸自动设置响应的内容类型及编码。

二、中间件

❄️1.什么是中间件

中间件: 就是一堆方法可以接收客户端发来的请求、可以对请求做出回应、也可以将请求交给下一个中间件继续处理。
中间件组成:中间件方法请求处理函数
中间件方法: 由Express提供,负责拦截请求,请求处理函数由开发人员提供,负责处理请求。

app.get('请求路径','处理函数');  //用来接收get请求
app.post('请求路径','处理函数'); //用来接收post请求

next()

app.get('/', (req,res) => {
  res.send('你好,首页!');
  next();  //没有next中间匹配成功后下一个中间件就执行了
})
app.get('/', (req,res) => {
  res.send('你好,首页!');
})

❄️2.app.use中间件用法

app.use匹配所有的请求方式,可以直接传入请求处理函数,代表接收所有的请求。

app.use((req,res,next) => {
  console.log(req.url);
  next();
})

app.use第一个参数也可以传入请求地址,表示无论什么请求方式,只要是请求这个请求地址就接收这个请求。

app.use('/admin',(req,res,next) => {  //next将请求交给下一个中间件
  console.log(req.url);
  next();
})

❄️3.中间件应用

路由保护,客户端访问需要登录的页面时,未登录则拦截请求。

const express = require('express');
const app= express();

app.use((req,res,next) => {
  console.log(req.url);
  next();
})
app.listen(3000);
console.log('网站服务器启动成功');

网站维护公告,在所有路由最上面定义中间件,直接为客户端响应网站正在维护中。

❄️4.错误处理中间件

错误处理中间件:是一个集中处理错误的地方。

app.use((err,req,res,next) => {
  res.status(500).send('服务器发生未知错误');
})

异步函数出错时,需要利用next()手动触发错误处理中间件

/示例代码/
const express = require('express');
const fs = require('fs');

const app = express();
app.get('/index', (req, res,next) => {
  fs.readFile('./index.html','utf8',(err,result) => {
    if(err != null){
      next(err)
    } else {
      res.send(result)
    }
  })
})

❄️5.异步函数async错误捕获

node.js中,异步API的错误信息是通过回调函数callback捕获的,支持promise对象的异步API发生错误通过catch方法捕获,异步函数执行发生错误呢?
try catch可以捕获异步函数以及同步代码在执行过程中发生的错误

/语法使用/
app.get('/', async(req,res,next) => {
  try{
    await User.find({name: '张三'});  //可能出错的代码
  } catch(ex) {
    next(ex);  //ex为错误信息
  }
})

三、Express请求处理

❄️1.构建模块化路由

const express = require('express')
const app = express();
//创建路由对象
const home = express.Router();  //Router()方法
//将路由的请求路径进行匹配
app.use('/home', home);
//在home路由下继续创建二级路由  /home/index
home.get('/index', () => {
  res.send('欢迎来到首页');
});
modules.exports = home;  //导出

❄️2.模块化路由实际使用案例

home.js-路由模块
const express = require('express')
const home = express.Router();
home.get('/index', () => {
  res.send('欢迎来到首页');
});
modules.exports = home;  //导出
admin.js-路由模块
const express = require('express')
const admin= express.Router();  
admin.get('/index', () => {
  res.send('欢迎来到管理页');
});
modules.exports = admin;  //导出
app.js-使路由模块生效
const express = require('express')
const app = express();

const home = require('./route/home');  //导入-('路径')
const admin = require('./route/admin');  //导入-('路径')
app.use('/home', home);  //匹配路径,访问/home/index
app.use('/admin', admin);  //匹配路径,访问/admin/index
app.listen(3000);

❄️3.GET参数的获取

GET参数的获取Express框架中使用req.query获取,框架内部会将GET参数转换成对象并返回。意义就是不再需要解析url来获取GET参数

const express = require('express')
const app = express();
//接收请求
app.get('/index', (req, res) => {
  //接收请求参数
  console.log(req.query);  /req.query就是参数{}但是需要用?传递/
})

Express路由参数

app.get('/find/:id', (req,res) => {});  /:id就是请求参数{id: 123}/
localhost:3000/find/123

代码示例:

const express = require('express')
const app = express();
const bodyParser = require('body-parser');

app.get('/index/:id/:name', (req,res) => {
  res.send(req.params)  //req.params就是路由参数,需要用/传递
})
app.listen(3000);

❄️4.POST参数的获取

POST参数的获取Express中接收post请求参数需要借助第三方模块body-parser

const express = require('express')
const app = express();
//引入body-parser模块
const bodyParser = require('body-parser');
//配置body-parser模块
app.use(bodyParser.urlencoded({ extended: false }));  //urlencoded()方法
//接收请求
app.post('/add', (req, res) => {
  //接收请求参数
  console.log(req.body);  //req.body就是参数
})

❄️5.静态资源的处理

静态资源的处理:通过Express内置的express.static可以方便的托管静态文件,例如img、CSS、JavaScript文件等。

app.use(express.static('public'));  //public是目录

现在,public目录下面的文件就可以访问了,示例代码如下

const express = require('express')
const app = express();
const path = require('path');

//实现静态资源访问功能
app.use(express.static(path.join(__dirname, 'public')))

app.listen(3000);

四、express-art-template模板引擎

❄️1.模板引擎

模板引擎:为了使art-template模板引擎能够更好的Express框架结合,模板引擎官方在原art-template基础上封装了express-art-template
安装:使用npm install art-template express-art-template命令进行安装。

const express = require('express')
const app = express();
const path = require('path');
//当渲染后缀为art模板时,使用express-art-template
app.engine('art', require('express-art-template'));
//设置模板存放目录
app.set('views', path.join(__dirname, 'views'));  /app.set('views','文件夹路径')/
/渲染模板时不写后缀,默认拼接art后缀/
/设置以上信息是为了使用render()方法/
app.get('/', (req, res) => {
  渲染模板
  res.render('index');    //res.render('模板名',{模板的值});  
})
app.listen(3000);

render()作用:将所有配置拼接,将拼接结果响应给客户端。

❄️2.app.local对象

app.local作用:将公共变量设置到app.local对象下,这个数据在所有的模板中都可以获取到,不需要重复加载。

//示例代码
const express = require('express')
const app = express();
const path = require('path');
app.engine('art', require('express-art-template'));
app.set('views', path.join(__dirname, 'views'));  

app.local.users = [{ name: '张三', age: 25 },{ name: '李四', age: 19 }]

app.get('/index', (req, res) => {
  res.render('index', {msg: '首页'}); 
})
app.get('/list', (req, res) => {
  res.render('list', {msg: '列表页'}); 
})
app.listen(3000);
//index.art文件
{{msg}}
<ul>
  {{each users}}
  <li>
    {{$value.name}}
    {{$value.age}}
  li>
  {{each}}
ul>
//list.art文件
{{msg}}
<ul>
  {{each users}}
  <li>
    {{$value.name}}
    {{$value.age}}
  li>
  {{each}}
ul>

项目部分我没有看,后续有时间会再补全


第四章 前后端交互Ajax

一、Ajax编程基础

⭐⭐Ajax概述

  • 传统网站(node)存在的问题:❶网速慢情况下页面加载时间长;❷表单提交后,如果一项内容不合格,需要重新填写所有内容;❸页面跳转,重新加载页面(表头等),造成资源浪费。
  • Ajax概述:是浏览器提供的一套方案,可以实现页面无刷新更新数据,提高用户浏览网页应用的体验。
  • Ajax应用场景:❶页面上拉加载更多数据;❷列表数据无刷新分页;❸表单项离开焦点数据验证;❹搜索框提示文字下拉列表。
  • Ajax运行环境Ajax技术需要运行在网站环境中才能生效,所以需要网站服务器。

二、Ajax运行原理及实现

  • Ajax运行原理:Ajax相当于浏览器发送请求与接收请求的代理人,以实现在不影响用户浏览器的情况下,局部更新页面数据。
    前端学习笔记____前后端交互Node+MongoDB+Express+Ajax_第4张图片

⭐1.Ajax的实现步骤

1.创建Ajax对象
var xhr = new XMLHttpRequest();
2.告诉Ajax请求地址及请求方式
xhr.open('get', 'http://www.example.com');  /('请求方式','请求地址')/
3.发送请求
xhr.send();  /服务器响应时间受网速影响故不确定何时收到响应,就不能直接用send()拿到响应结果因此衍生出4/
4.获取服务器端给与客户端的响应数据
xhr.onload = function() {
  console.log(xhr.responseText);  /responseText属性保存的就是响应文本/
}

⭐2.服务器响应的数据格式

  • 在真实项目中,服务器端大多数情况下会以JSON对象作为响应数据的格式。当客户端拿到响应数据时,要将JSON数据和HTML字符串进行拼接,然后将拼接结果展示在页面中。
  • 在http请求与响应的过程中,无论是请求参数还是响应内容,如果是对象类型都会转换成对象字符串进行传输。
  • 将json字符串转换成json对象(window.)JSON.parse()
//示例代码-服务器返回数据客户端如何处理
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com'); 
xhr.send();  
xhr.onload = function() {
  var responseText = JSON.parse(xhr.responseText);  /将json字符串转换成json对象/
  var str = '

' + responseText.name + '

'
document.body.innerHTML = str; //显示到页面中 }

⭐3.使用Ajax如何传递请求参数

  • 对比传统网站表单提交
<form method='get' action='http://www.example.com'>
  <input type='text' name='username'>
  <input type='pessword' name='pessword'>
form>


  • GET请求方式xhr.open('get', 'http://www.example.com?name=zhangsan$age=18');
  • POST请求方式xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.send('name=zhangsan&age=20');固定,设置请求报文setRequestHeader(‘报文属性名’,‘值’)。
//示例代码-HTML
<p><input type='text' id='username'>p>
<p><input type='text' id='age'>p>
<p><input type='button' value='提交' id="btn">p>
//示例代码-GET请求方式.js
var btn = dcunment.getElementById('btn');
var username = dcunment.getElementById('username');
var age = dcunment.getElementById('age');
btn.onclick = function(){
  var xhr = new XMLHttpRequest();
  var nameValue = username.value;
  var ageValue = age.value;
  var parmas = 'username=' + nameValue + '&age=' + ageValu;  /传统表单是自己拼接好的,但在ajax里需要自己拼接/
  xhr.open('get', 'http://www.example.com/get?' + parmas ); 
  xhr.send(); 
  xhr.onload = function() {
    var responseText = JSON.parse(xhr.responseText);
    console.log(responseText)
  }
}
//示例代码-post请求方式.js
var btn = dcunment.getElementById('btn');
var username = dcunment.getElementById('username');
var age = dcunment.getElementById('age');
btn.onclick = function(){
  var xhr = new XMLHttpRequest();
  var nameValue = username.value;
  var ageValue = age.value;
  var parmas = 'username=' + nameValue + '&age=' + ageValu;
  xhr.open('post', 'http://www.example.com/post'); 
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');  /post特有/
  xhr.send(parmas); 
  xhr.onload = function() {
    var responseText = JSON.parse(xhr.responseText);
    console.log(responseText)
  }
}

⭐4.post请求参数的格式

  • Content-Type类型;application/x-www-form-urlencoded
name=zhangsan&age=20&sex=;  /字符串格式/
  • Content-Type类型:application/json(在请求头中指定Content-Type属性的值是application/json,告诉服务器端当请求参数的格式是json)。 将json对象转换为json字符串JSON.stringfy()
{name: 'zhangsan', age: '20', sex: '男'}  /字符串格式/
//示例代码
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://www.example.com/post'); 
/通过请求头告诉服务器端,客户端段向服务器传递的请求参数的格式是什么/
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringfy({name: 'zhangsan', age: '20'})); 
xhr.onload = function() {
  console.log(xhr.responseText);
}
  • 注意get请求是不能提交json对象数据格式的,传统网站的表单提交也是不支持json对象数据格式的

⭐5.获取服务器端的响应(了解)

⑴ Ajax状态码

  • Ajax状态码:在创建ajax对象,配置ajax对象,发送请求,以及接收完服务器端响应数据,这个过程中的每一个步骤都会对应一个数值,即Ajax状态码。
状态码 含义
0 请求未初始化( 还没有调用open() )
1 请求已经建立,但是还没有发送( 还没有调用send() )
2 请求已经发送
3 请求正在处理中,通常响应中已经有部分数据可以用了
4 响应已经完成,可以获取并使用服务器的响应
  • 当Ajax状态码发生变化时将自动触发onreadystatechange事件,获取Ajax状态码:xhr.readyState
//示例代码
var xhr = new XMLHttpRequest();
console.log(xhr.readyState);  //执行结果依次为  0
xhr.open('get', 'http://www.example.com/post'); 
console.log(xhr.readyState);  //执行结果依次为  1
xhr.onreadystatechange = function(){
  console.log(xhr.readyState);  //执行结果依次为  2 3 4
  if(xhr.readyState == 4){
    console.log(xhr.responseText);
  }
}
xhr.send(); 

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

⑵ 两种获取服务器端响应方式的区别

区别描述 onload事件(推荐) onreadystatechange事件
是否兼容IE低版本 不兼容 兼容
是否需要判断Ajax状态码 不需要 需要
被调用次数 一次 多次

⭐3.Ajax错误处理

  • 网络畅通,服务器端能接收到请求,服务器端返回的结果不是预期结果。
    可以判断服务器端返回的状态码,分别进行处理,xhr.status获取http状态码。
<button id="btn">发送Ajax请求button>
<script type="text/javascript">
  var btn = dcunment.getElementById('btn');
  btn.onclick = function(){
    var xhr = new XMLHttpRequest();
    xhr.open('get', 'http://www.example.com/get'); 
    xhr.send(); 
    xhr.onload = function() {
      if(xhr.status == 400){
        alert('请求出错!')
      }
      console.log(xhr.responseText);
    }
  }
script>
  • 网络畅通,服务器端没有接收到请求,返回404状态码。
    检查请求地址是否错误。
  • 网络畅通,服务器能接收到请求,服务器端返回500状态码。
    服务器端错误,找到后端程序员进行沟通。
  • 网络中断,请求无法发送到服务器端。
    触发xhr.onerror事件,在onerror事件处理函数中对错误进行处理。

⭐4.低版本IE浏览器的缓存问题

  • 问题在低版本浏览器中,Ajax请求有严重的缓存问题,即在请求地址不发生变化的情况下,只有第一次请求会真正发送到服务器端,后续的请求都会从浏览器的缓存中获取结果。即使服务器端的数据更新了,客户端依旧拿到的是缓存中的旧数据。
    解决方案:在请求地址的后面加请求参数,保证每一次请求中的请求参数的值不同。
//示例代码
xhr.open('get', 'http://www.example.com?get=' + Math.random());

三、Ajax异步编程

⭐1.Ajax封装

//封装好的代码
<script type="text/javascript">
  function ajax(options){
    //创建ajax对象
    var xhr = new XMLHttpRequest();
    var params = '';
    //循环用户传递进来的格式参数
    for(var attr in options.data){
      //将参数装换成字符串雷幸福
      params += attr + '=' + options.data[attr] + '&';
    }
    params = params.substr(0, params.length - 1)
    if(options.type == 'get') options.url = options.url + '?' + params;
    //配置ajax对象
    xhr.open('options.type', 'options.url'); 
    if(options.type == 'post'){
      var contentType = options.header['Content-Type']
      xhr.setRequestHeader('Content-Type', options.header['Content-Type']);
      if(contentType == 'application/json'){
        xhr.send(JSON.stringify(options.data)); 
      } else {
        xhr.send(params);
      }
    } else xhr.send(); 
    xhr.onload = function(){
      //判断请求是否成功
      if(xhr.status == 200){
        options.success(xhr.responseText, xhr);  //成功
      } else {
        options.error(xhr.responseText, xhr);  //失败
      }

    }
  }
script>
//调用
ajax({
  type: 'get',
  url: 'http://www.example.com',
  data: {
    name: 'zhangsan',
    age: 18
  },
  header: {
    'Content-Type': 'application/json'
  },
  success: function(data){
    console.log(data);
  }
})
  • 视频173&174没看完。

⭐2.客户端模板引擎

  • 作用将服务器的json字符串转换,使用模板引擎的模板语法,可以将数据和HTML拼接起来。
  • 官方地址:https://aui.github.io/art-template/zh-cn/index.html

使用步骤

  1. 下载art-template模板引擎文件并在HTML页面中引入库文件。
  2. 准备art-template模板。
  3. 告诉模板引擎将哪一个模板和哪个数据进行拼接。
    var html = template('tpl', {username: 'zhangsan', age: '20' }); //template('id', "数据")
  4. 将拼接好的html字符串添加到页面中。
    document.getElementById('container').innerHTML = html; //container容器,自定义
  5. 通过模本语法告诉模板引擎,数据和html字符串要如何拼接。
  • 案例:视频176-179没看。

四、FormData对象

⭐1.FormData对象的作用

  • FormData类型:是XMLHttpRequest 2级定义的,它是为序列化表以及创建与表单格式相同的数据提供便利。
  • 作用:❶模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的形式。(即将form中的所有表单元素的name和value组装成一个queryString);❷异步上传二进制文件。
  • 优点:与普通Ajax相比,使用FormData的最大优点是可以异步上传二进制文件

⭐2.FormData对象的使用

⑴ 模拟HTML表单情况

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);
示例代码-客户端
<body>
  <form id="form">
    <input type="text" name="username" />
    <input type="password" name="password" />
    <input type="button" value="提交" id="btn" />
  form>
  <script>
    var btn = document.getElementById('btn');
    var form = document.getElementById('form');
    btn.onclick = function(){
      var formData = new FormData(form);  /不用获取每个input中的值可以直接提交,这就是FormData的作用/
      var xhr = new XMLHttpRequest();
      xhr.open('post', 'http://www.example.com');  /这里请求方式不能为get,不知道为什么有点白学了/
      xhr.send(formData);  //发送请求
      xhr.onload = function(){
        if(xhr.status == 200){
          console.log(xhr.responseText, xhr);
        }
      }
    }
  script>
body>

⑵ FormData二进制文件上传

1.准备HTML表单

<input type="file" id="file">

2.将HTML表单转化为formData对象,提交

var file = document.getElementById('file');
//当用户选择文件的时候
file.onchange = function(){
  //创建空表单对象
  var formData = new FormData(form);
  //将用户选择的二进制文件追加到表单对象中
  formData.append('attName', this.files[0]);  /attName为自定义,文件存在file对象中的file属性中/
  //配置ajax对象,请求方式必须为post
  var xhr = new XMLHttpRequest();
  xhr.open('post', 'http://www.example.com');  /请求方式必须为post/
  xhr.send(formData);
  xhr.onload = function(){
    if(xhr.status == 200){
      console.log(xhr.responseText, xhr);
    }
  }
}
示例代码-客户端
<body>
  <div class="container">
    <div class="form-group">
      <label>请选择文件label>
      <input type="file" id="file">
    div>
  div>
  <script type="text/javascript">
    var file = document.getElementById('file');
    file.onchange = function() {
      var formData = new FormData(form);
      formData.append('attName', this.files[0]);  /attName为自定义,文件存在file对象中的file属性中/
      var xhr = new XMLHttpRequest();
      xhr.open('post', 'http://www.example.com');
      xhr.send(formData);
    }
  script>
body>

⑶ FormData文件上传进度展示

//当用户选择文件的时候
file.onchange = function(){
  /文件上传过程中持续触发onprogress事件(progress进度)/
  xhr.upload.onprogress = function(ev){
    //当前上传文件大小/文件总大小,再将结果转换为百分数
    //将结果赋值给进度条的宽度属性
    bar.style.width = (ev.loaded/ev.total) * 100 + '%';
  }
} 
示例代码-客户端
<body>
  <div class="container">
    <div class="form-group">
      <label>请选择文件label>
      <input type="file" id="file">
      <br/>
      <div class="progress">
        <div class="progress-bar" style="width: 0%" id="bar">0%div>
      div>
    div>
  div>
  <script type="text/javascript">
    var file = document.getElementById('file');
    var dar = document.getElementById('bar');
    file.onchange = function() {
      var formData = new FormData(form);
      formData.append('attName', this.files[0]);  /attName为自定义,文件存在file对象中的file属性中/
      var xhr = new XMLHttpRequest();
      xhr.open('post', 'http://www.example.com');
      file.onchange = function(){
        xhr.upload.onprogress = function(ev){  /upload对象保存上传相关的事件,ev事件对象/
           var result = (ev.loaded/ev.total) * 100 + '%';
           bar.style.width = result;
           bar.innerHTML = result;
        }
      } 
      xhr.send(formData);  //发送请求
    }
  script>
body>

⑷ FormData文件上传图片即时预览

  • 目前在node中式无法实现文件上传图片即时预览,即时预览将图片上传到服务器端以后,服务器端通常都会将图片地址作为相应数据传输到客户端,客户端可以从响应数据中获取图片地址,然后将图片再显示在页面中。
  • 比较少用暂时没写,需要再补。

⭐3.FormData对象的常用实例方法

  • 获取表单对象中属性的值。formData.get('key');
  • 获取key为username的所有值,返回一个数组。formdata.getAll("username");
  • 设置表单对象中属性的值,应用场景:表单数据的二次处理。formData.set('key', 'value');
  • 删除表单对象中属性的值。formData.delete('key');
  • 向表单对象中追加属性值。formData.append('key', 'value');
  • 判断是否存在某条数据,存在返回true,不存在返回false。formdata.has(key);
  • set()与append()区别:在属性名已存在的情况下,set()会覆盖已有键名的值,append会保留两个值。
<body>
  <form id="form">
    <input type="text" name="username" />
    <input type="password" name="password" />
    <input type="button" value="提交" id="btn" />
  form>
body>
<script>
  var btn = document.getElementById('btn');
  var form = document.getElementById('form');
  btn.onclick = function(){
    var formData = new FormData(form);
    formData.get('username');  //获取表单对象中属性的值
    var xhr = new XMLHttpRequest();
    xhr.open('post', 'http://www.example.com');
    xhr.send(formData);
    xhr.onload = function(){
      if(xhr.status == 200){
        console.log(xhr.responseText, xhr);
      }
    }
  }
script>

五、同源政策

⭐1.Ajax请求限制

  • Ajax只能向自己服务器发送请求。比如现在有一个A网站、B网站,A网中HTML文件只能向网站服务器中发送Ajax请求,B网站中HTML也是一样,但是A网站是不能向B网站发送Ajax请求,同理B网站也是一样。

⭐2.什么是同源

  • 同源:如果两个页面拥有相同的协议域名端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。
  • 同源政策的目的:同源政策是为了保证用户信息安全,防止恶意的网站窃取数据。最初的同源政策是指A网站在客户端设置的Cookie,B网站是不能访问的。

⭐3.解决同源限制

使用JSONP解决同源限制问题

  • 这种解决方案需要前后端配合解决。JSONP是json with padding简写
  1. 将不同源的服务器端请求地址写在script标签的src属性中
<script src="www.example.com">script>
<script src="https://cdn.example.com/jquery/jquery.min.js">script>
  1. 服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数
const data = ' fn({name: "张三", age:"20"})';
res.send(data);
  1. 在客户端全局作用域下定义函数fn
function fn(data) {}
  1. 在fn函数内部对服务器端返回的数据进行处理
function fn(data){ console.log(data); }
  • 示例代码
示例代码-客户端
<body>
  <script>
    function fn(data){
      console.log('客户端的fn函数被调用了')  //执行结果客户端显示 客户端的fn函数被调用了  {name: "张三", age:"20"}
      console.log(data)
    }
  script>
  
  <script src="http://localhost:3001/tast">script>
    
body>
示例代码-非同源服务器端3001
const express = require('express');
const path = require('path');
const app = express();  //创建web服务器

app.use(express.static(path.join(__dirname, 'public')));
app.get('/test', (req,res) => {
  const result = 'fn({name: "张三", age:"20"})';  /立即调用/
  res.send('result');
})

app.listen(3001);
console.log('服务器启动成功');  

⭐4.JSONP代码优化

  • JSONP代码优化:❶客户端需要将函数名称传递到服务器端;❷将script请求的发送变成动态请求。
  • 存在问题:不能控制请求服务器时间,解决办法如下:
代码示例-客户端  点击按钮之后才触发请求
<body>
  <button id="btn">点我发送请求button>
  <script>
    function fn2(data){
      console.log('客户端的fn函数被调用了');
      console.log(data)
    }
  script>

  <script type="text/javascript">
    var btn = document.getElementById('btn');
    btn.onclick = function(){
      var script = document.createElement('script');
      script.src = 'http://localhost:3001/better';
      document.body.appendChild(script);
      /当请求加载完毕时将script去掉,防止反复点击造成浪费/
      script.onload = function(){
        document.body.removeChild(script);
      }
    }
  script>
body>
示例代码-服务器端
app.get('/better', (req,res) => {
  const result = 'fn2({nama: "张三"})';
  res.send(result);
})
  • 存在问题,每次函数名字改变服务器端也需要一起改变,用callback解决如下:
代码示例-客户端  点击按钮之后才触发请求
<body>
  <button id="btn">点我发送请求button>
  <script>
    function fn2(data){
      console.log('客户端的fn函数被调用了');
      console.log(data)
    }
  script>

  <script type="text/javascript">
    var btn = document.getElementById('btn');
    btn.onclick = function(){
      var script = document.createElement('script');
      script.src = 'http://localhost:3001/better?callback=fn2';  /callback方法/
      document.body.appendChild(script);
      script.onload = function(){
        document.body.removeChild(script);
      }
    }
  script>
body>
示例代码-服务器端
app.get('/better', (req,res) => {
  const fnNama = req.query.callback;  /接收客户端传递的名称fn2/
  const result = fnNama + '({nama: "张三"})';
  res.send(result);
})
  • 封装jsonp函数,方便请求发送
<body>
  <button id="btn">点我发送请求button>
  <script>
    //function fn2(data){
      //console.log('客户端的fn函数被调用了');
      //console.log(data); 
    //}  放在了success中
  script>
  <script>
    var btn = document.getElementById('btn');
    btn.onclick = function(){
      jsonp({
        url: 'http://localhost:3001/better',
        data: { age: '18' },
        success: function(){
          console.log('客户端的fn函数被调用了');
          console.log(data);
        },
      })
    };
    function jsonp(options){
      var script = document.createElement('script');
      //拼接字符串的变量
      var parmas = '';
      for(var attr in options.data){
        params += '&' + attr + '=' + options.data[attr];
      }
      /因为options.success现在已经不是全局函数了,请求返回结果时会找不到响应函数,故要将他变成全局函数/
      var fnName = 'myJsonp' + Math.random().toString().replace('.',''); //生成随机名
      script.src = options.url + '?callback=' + fnName + parmas;
      window[fnNme] = options.success;  /不能将函数名定义死,容易出现覆盖问题/
      document.body.appendChild(script);
      script.onload = function(){
        document.body.removeChild(script);
      }
    }   
  script>
body>

//请求地址为http://localhost:3001/better?myJsonp1894586655445&age=18
//执行结果  客户端的fn函数被调用了   {nama: "张三"}
示例代码-服务器端
app.get('/better', (req,res) => {
  //const fnNama = req.query.callback;  
  //将参数转换成字符串进行响应
  //const data = JSON.stringify({nama: "张三"});
  //const result = fnNama + '(' + data ')';
  //res.send(result);

  res.jsonp({nama: "张三"});  /jsonp方法就是上述一些列代码的作用,即服务器端代码优化/
})

案例:腾讯天气

⭐5.访问非同源数据(跨域),服务器端解决方案

  • 同源政策是浏览器给予Ajax技术的限制,服务器端是不存在同源政策限制。
    前端学习笔记____前后端交互Node+MongoDB+Express+Ajax_第5张图片
示例代码-A浏览器端
<body>
  <button id="btn">点我发送请求button>
  <script src="/js/ajax.js">script>
  <script>
    var btn = document.getElementById('btn');
    btn.onclick = function(){
      ajax({
        type: 'get',
        url: 'http://localhost:3000/server',
        success: function(data){
          console.log(data);
        }
      })
    };
  script>
body>

//控制台执行结果为asd,页面响应ok
示例代码-A服务器端
const express = require('express');
const path = require('path');
const request = request('request');  /用于发送跨服务器请求,返回request方法/
const app = express();  //创建web服务器
app.use(express.static(path.join(__dirname, 'public')));  //静态资源访问服务功能

app.get('/server', (req, res) => {
  request('http://localhost:3001/cross', (err,response,body) => {
    console.log(err);  /在node中执行结果为null没有错误/
    console.log(response);  /在node中执行结果为服务器响应信息/
    console.log(body);  /在node执行结果为B服务器端响应结果/
    res.send('asd');
  })
})
app.listen(3000);
console.log('服务器启动成功');
示例代码-B服务器端
const express = require('express');
const path = require('path');
const app = express();  //创建web服务器
app.use(express.static(path.join(__dirname, 'public')));  //静态资源访问服务功能

app.get('/cross', (req, res) => {
  res.send('ok');
})
app.listen(3001);
console.log('服务器启动成功');

⭐6.cookie

  • cookie的作用:服务器可以通过cookie识别客服端,实例应用-登录功能。
    前端学习笔记____前后端交互Node+MongoDB+Express+Ajax_第6张图片

withCredentials属性

  • 在使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息。withCredentials属性解决跨域时不携带cookie的问题,实例应用-当一个系统拥有不同服务器时,跨域后退出登录的问题。
  • withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false。
  • 客户端设置Access-Control-Allow-Credentials:true允许客户端发送请求时携带cookie。
代码示例-客户端
<body>
  <div class="container">
    <form id="loginForm">
      <div class="form-group">
        <label>用户名label>
        <input type="text" name="username" class="form-control" placeholder="请输入用户名">
      div>
      <div class="form-group">
        <label>密码label>
        <input type="password" name="password" class="form-control" placeholder="请输入密码">
      div>
      <input type="button" class="btn" value="登录" id="loginBtn" />
      <input type="button" class="btn" value="检测用户登录状态" id="checkLogin" />
    form>
  div>
  
  <script type="text/javascript">
    var loginBtn = document.getElementById('loginBtn');
    var checkLogin = document.getElementById('checkLogin');
    var loginForm = document.getElementById('loginForm');
    loginBtn.onclick = function(){
      var formData = new FormData(loginForm);
      var xhr = new XMLHttpRequest();
      xhr.open('post', 'http://localhost:3001/login');
      xhr.withCredentials = true;  /当发送跨域请求时,携带cookie信息/
      xhr.send(formData);
      xhr.onload = function(){
        console.log(xhr.responseText);  //输出服务器返回结果
      };
    };
    //检测用户登录状态
    checkLogin.onclick = function(){
      var formData = new FormData(loginForm);
      var xhr = new XMLHttpRequest();
      xhr.open('get', 'http://localhost:3001/checkLogin');
      xhr.send();
      xhr.onload = function(){
        console.log(xhr.responseText);
      };
    };
  script>
body>
示例代码js-服务器端代码,3001端口
const express = require('express');
const path = require('path');
const app = express();  //创建web服务器
//拦截所有请求
app.use((req, res, next) => {
  //1.允许哪些客户端访问我,*代表允许所有客户端访问我
  //注意:如果跨域请求中涉及cookie信息传递,值不可以为*
  res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.header('Access-Control-Allow-Methods', 'get,post');
  res.header('Access-Control-Allow-Credentials', true);  /允许跨域请求携带cookie/
  next();
});  

app.get('/login', (req, res) => {
  var form = formidable.IncomingForm();  //创建表单解析对象
  //解析表单
  form.parse(req, (err,fields,file) => {
    //接收客户端传递过来的用户名和密码
    const { username, password } = fields;
    if(username == 'itheima' && password == '123456'){
      //设置session
      req.session.isLogin = true;
      res.send({ message: '登录成功' });
    } else {
      res.send({ message: '登录失败' });
    }
  })
  res.send('ok');
});

app.listen(3001);
console.log('服务器启动成功');

六、$.ajax()

⭐1.$.ajax()方法概述

  • $.ajax()方法作用:发送Ajax请求。
语法结构js
$.ajax({
  type: 'get',  /请求类型/
  url: 'http://www.example.com',  /请求地址/
  data: { name: 'zhangsan', age: '20' },  /向服务器端发送的参数,格式{data:'name=zhangsan&age=20'}/
  contentType: 'application/x-www-form-urlencoded',  /设置向服务器端发送参数的格式类型/
  beforeSend: function(){  /请求发送之前做处理,例如对请求参数值的格式进行验证提高用户体验/
    //return false
  },
  success: function(response){},  /函数请求成功以后被调用/
  error: function(xhr){}  /请求失败时触发/
});

  data: JSON.stringify({ name: 'zhangsan', age: '20' }),  /向服务器端发送的参数json格式/
  contentType: 'application/json',  /设置向服务器端发送参数的格式类型/
<body>
<button id="btn">点我发送请求button>
  <script src="/js/jquery.min.js">script>
  <script>
   $('btn').on('click', function(){
     $.ajax({
       type: 'get',
       url: 'http://localhost:3000/base',
       data: { name: 'zhangsan', age: '20' },
       contentType: 'application/x-www-form-urlencoded',
       success: function(response){
        console.log(respons);  /respons为服务器返回数据,方法内部会自动将json字符串转换为json对象/
       },
       error: function(xhr){}
     });
   })
  script>
body>

205节之后视频内容暂时没有更新,待续…

你可能感兴趣的:(自学前端,怎么学习前端,ajax)