? 作者主页:?仙女不下凡?
? 前言介绍:以下? 内容都是我个人对于前端知识的总结,会定期更新欢迎持续关注!
? 欢迎点赞 ? 收藏 ⭐留言 ? 如有错误敬请指正!
??前言
?学习视频地址: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是有 ECNAScript 及 Node环境 提供的一些附加API组成的,包括读取文件、网络路径等一些更强大的API。
?Node.js基础语法: ECNAScript的语法都可以使用。
?Node.js全局对象: 浏览器中全局对象是window,Node中全局对象是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
?⑵exports与module.exports关系:exports是module.exports的别名,当exports与module.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转换成ES5、less文件转换成普通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任务就可以了。
示例代码-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.页面执行结果<h2>写响应内容</h2> 不识别HTML标签
✨3.HTTP协议
?HTTP协议概念(超文本传输协议)
?请求报文的请求方式: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/json用 mime模块 处理判断当前接收的模块类型使用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 = '<ul>';
for(var i = 0; i <ary.length; i++) {
str +=`<li>\
<span>` + arr[i].name + `</span>\
<span>` + arr[i].age + `</span>\
</li>`;
}
str += '</ul>'
<!--使用模板引擎的写法-->
<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.js与Express框架对比-获取请求参数
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相当于浏览器发送请求与接收请求的代理人,以实现在不影响用户浏览器的情况下,局部更新页面数据。

⭐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 = '<h2>' + responseText.name + '</h2>'
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>
<!--- http://www.example.com?username=zhangsan&pessword=123456--->
<!--传统网站是用"="拼接的值-->
- 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
使用步骤
- 下载art-template模板引擎文件并在HTML页面中引入库文件。
<script src="./js/template-web.js"></script> - 准备art-template模板。
<script id="tpl" type="text/html"> <div class="box"></div> </script> - 告诉模板引擎将哪一个模板和哪个数据进行拼接。
var html = template('tpl', {username: 'zhangsan', age: '20' }); //template('id', "数据") - 将拼接好的html字符串添加到页面中。
document.getElementById('container').innerHTML = html; //container容器,自定义 - 通过模本语法告诉模板引擎,数据和html字符串要如何拼接。
<script id="tpl" type="text/html"> <div class="box"> {{username}} </div> </script>
- 案例:视频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简写
- 将不同源的服务器端请求地址写在script标签的src属性中
<script src="www.example.com"></script>
<script src="https://cdn.example.com/jquery/jquery.min.js"></script>
- 服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数
const data = ' fn({name: "张三", age:"20"})';
res.send(data);
- 在客户端全局作用域下定义函数fn
function fn(data) {}
- 在fn函数内部对服务器端返回的数据进行处理
function fn(data){ console.log(data); }
- 示例代码
示例代码-客户端
<body>
<script>
function fn(data){
console.log('客户端的fn函数被调用了') //执行结果客户端显示 客户端的fn函数被调用了 {name: "张三", age:"20"}
console.log(data)
}
</script>
<!-- 1.将非同源服务器端的请求地址写在script标签的src属性中 -->
<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技术的限制,服务器端是不存在同源政策限制。

示例代码-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识别客服端,实例应用-登录功能。

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>