一、NodeJS
1.1执行代码
1.1.1 - cmd执行
1.打开文件所在目录
2.地址栏点击并输入cmd回车
3.在弹出来的cmd窗口输入 node指定文件地址
1.1.2 - 在编辑器终端执行
在vscode里面通过 “终端” -> "新终端" ,或者使用快捷键 ctrl + ~
打开vscode的命令行窗口
二、NodeAPI学习
2.1 NodeJS 组成
- ECMAScript 语法 , 功能
- Node标准库 Node官方自带的功能API
- Node第三方库 开发者在开发过程中的常用代码
2.2浏览器的组成
- ECMACScript 语法功能
- DOM 操作页面元素的API
- BOM 操作浏览器功能的AIPI
注意:服务器里面是没有页面的,没有浏览器功能的,所以NodeJS里面没有必要有DOM和BOM
2.2NodeJS 标准库
2.2.1 fs模块
// 1. 引入fs模块 , node里面几乎所有的标准库都要先引入才能使用
const fs = require('fs')
// 2. 调用readFile方法 , 并指定编码
// 路径 编码 回调函数
fs.readFile('./page/index.html','utf-8',(error,data)=>{
console.log(data)
})
2.2.2 path模块
path.join 方法
const path = require('path')
// join的作用是把多个片段拼接在一起,并解决不同平台的字符兼容问题
// __dirname 得到当前目录的路径
const dir = path.join(__dirname,'../page/index.html')
path.resolve 方法
//只需要给一个相对路径,就能得到一个绝对路径
const path = require('path')
const dir = path.resolve('../page/index.html')
3.1 搭建服务器代码
// 1. 引入http协议,node里面已经帮我们封装好了关于这部分的API
const http = require('http')
// 2. 创建一个服务器对象
const server = http.createServer()
// 3. 绑定ip和端口
server.listen('8080','127.0.0.1')
// 4. 服务器对象监听浏览器的请求
server.on('request',(request,response)=>{
// 5. 响应数据回浏览器
response.end('<h1>hello world!!!</h1>')
})
3.1.1 中文乱码问题
// 响应头中返回数据解析方式和数据编码格式
response.setHeader('Content-Type','text/html;charset=utf-8')
response.end('<h1>你好,世界!!!</h1>')
3.1.2 返回静态数据
const http = require('http')
// 引入fs模块
const fs = require('fs')
const server = http.createServer()
server.listen(8080,'127.0.0.1')
server.on('request',(request,response)=>{
// 读取出来指定的文件
fs.readFile('./views/index.html',(err,data)=>{
// 调用 响应回浏览器的方法把页面内容返回浏览器
response.end(data)
})
})
3.1.3 根据请求url返回不同的静态资源
要根据不同的url来返回不同的静态资源,那么就要在最开始的时候约定好,浏览器发什么url回服务器,服务器就返回对应的数据
如果请求 '/views/index.html' 我们就从服务器返回 index页面的内容
如果请求 '/css/index.css' 我们就从服务器返回 index.css 的内容
如果请求 '/views/list.html' 我们就从服务器返回 list页面的内容
server.on('request',(request,response)=>{
// 得到浏览器请求的url
console.log(request.url)
})
需要在request事件里面判断请求的url,并读取不同的资源返回即可
server.on('request',(request,response)=>{
// 返回index.html
if(request.url === '/views/index.html'){
// fs读取index.html , response.end() 返回
}
else if (request.url === '/views/list.html'){
// fs读取list.html , response.end() 返回
}
else if (request.url === '/css/index.css'){
// fs读取index.css , response.end() 返回
}
})
3.1.4 统一返回静态资源
我们fs读取的路径,事实上和我们约定的请求url是一样的
server.on('request',(request,response)=>{
fs.readFile(__dirname+request.url,(err,data)=>{
response.end(data)
})
})
有一个问题,我们能访问到这个网站下的所有资源,这样不安全,所以我们约定,只有几个固定的,用来放静态资源的文件夹才能被访问
server.on('request',(request,response)=>{
// 请求的url要以 /views 开关,才是静态请求
if(/^\/views/.test(request.url)){
fs.readFile(__dirname+request.url,(err,data)=>{
response.end(data)
})
}
})
3.1.5 处理动态数据
管这种处理动态请求的方式称呼为 : 接口
server.on('request',(request,response)=>{
// 判断url
if(reqeust.url === '/getArticles'){
// 返回一个数组给浏览器 - 但是不能直接返回一个数组,要先把数组转换为字符串,否则会报错
let json = JSON.stringify([
{id:1,title:'标题1',content:'内容1'},
{id:2,title:'标题2',content:'内容2'},
{id:3,title:'标题3',content:'内容3'}
])
response.send(json)
}
})
此时我们只要在页面中写ajax请求,请求这个接口,就能得到一个数组。
<ul id="parent"></ul>
<script>
$.ajax({
url:'http://127.0.0.1:8080/getArticles',
success(res){
// 服务器给我们的是一个字符串,先把字符串转换为数组
let arr = JSON.parse(res)
let str = ''
arr.forEach(e=>{
str += `<li>${e.title}</li>`
})
$('#parent').append(str)
}
})
</script>
三、NodeJS-模块化
3.1 CommonJS模块化
// 导出
module.exports = { 导出的数据 }
module.exports.键 = 导出的数据
exports.键 = 导出的数据
const 模块名称 = require('指定模块路径或者模块名称')
使用CommonJS模块化的写法的时候注意:
-
exports 不能重新赋值,无效
-
module.exports 重新赋值后,导出的对象就变成了这个对象
// 把动态请求的功能放在这个router.js里面
module.exports = function(req,res){
if(req.url === '/getArticle'){
res.end(文章数据)
}else if(req.url==='/login'){
res.end(登录结果)
}
// TODO
}
const http = require('http')
const fs = require('fs')
const path = require('path')
// 导入router.js里面导入的函数
const router = ruquire('./router.js')
const server = http.createServer()
server.listen(8080,'127.0.0.1')
server.on('request',(req,res)=>{
if(/^\/views/.test(req.url)){
fs.readFile(path.join(__dirname,req.url),(err,data)=>[
res.end(data)
])
}else{
// 调用函数处理动态数据
router(req,res)
}
})
3.2 ES Module(俗称es6模块化)
// 默认导出
export default 要导出的对象
// 按需导出
export { 要导出的数据 }
// 默认导入
import 模块名 from '模块或者路径'
// 按需导入
import {数据 , 数据 ...} from '模块或者路径'
// 混合导入
import 模块名,{数据 , 数据 ...} from '模块或者路径'
注意:
- 默认导入的名称不用和导出的那你一样
- 按需导入的数据名称要和按需导出的数据名称要一样
- 按需导入可以部分导入
// 默认导出
export default add
function add(a,b) { return a + b }
// 按需导出
export { add , reduce }
function reduce(a,b) { return a - b }
// 默认导入
import fn from './a.js'
// 按需导入
import {add} from 'a.js'
// 混合导入
import fn,{add,reduce} from './a.js'
注意:
-
后期我们使用ES Module的写法非常多,所以一定要掌握好
-
node环境下默认不支持ES Module的语法,需要:
a. 保证node版本在13及以上
b. 要使用.mjs结尾才能正常使用
四、NodeJS(ajax请求)
4.1 Express
Express 作为开发框架,因为它是目前最稳定、使用最广泛,而且 Node.js 官方推荐的唯一一个 Web 开发框架。
4.2 处理静态资源
浏览器以get方式请求数据
const express = require('express');
const app = express();
app.listen(8080)
app.use('/views',express.static('views'))
// 使用app.get监听浏览器的get请求
app.get('/getArticles',(req,res)=>{
// req , res 和我们之前写原生node一样,也是请求对象和响应对象
// 通过 req.query 得到请求带回的数据
console.log(req.query)
// 通过res.send()返回数据
res.send({
code:200,msg:'ok',
data : [ {id:1,title:'标题1'},{id:2,title:'标题2'},{id:3,title:'标题3'}, ]
})
})
我们只需在views目录里面有一个articles.html,并通过 http://127.0.0.1:3000/views/articles.html访问就可以在里面使用ajax发请求并得到数据。
<h1> artilces页面</h1>
<script src="jquery...js"></script>
<script>
$.ajax({
url:'http://127.0.0.1:8080/getArticles',
// 带数据回服务器
data : {pageIndex:1,pageSize:10},
success(res){
console.log(res)
}
})
</script>
4.3 处理post请求
const express = require('express');
const app = express();
app.listen(8080)
app.use('/views',express.static('views'))
// post请求带回的数据有多种格式,所以我们要先决定好能解决哪种格式
app.use(express.urlencoded({extened:true})) // 这是解析 key=value&key=value格式的
// 使用app.post监听浏览器的post请求
app.post('/login',(req,res)=>{
// 通过 req.body 得到请求带回的数据,一定是有了上面的app.use才能得到数据
console.log(req.body)
// 通过res.send()返回数据
res.send({
code:200,msg:'ok',
data : {
token: 'apsdiufpsaugipwerkmcasd034lijsdf...'
}
})
})
小结: express快速完成服务器开发
- 使用 express.static 处理静态资源
- 使用 app.get 监听get请求,通过 req.query 得到数据
- 使用 app.post 监听 post 请求,通过 express.urlencoded 解析数据,使用 req.body 得到数据
4.4 服务器端渲染(了解)
服务器端渲染,简称SSR
SSR(server side render)指的是把页面数据在服务器端的时候就先把动态数据写入返回数据里面,不需要再使用ajax请求回来再渲染。
这样做的好处有:
- 减少浏览器请求服务器的次数
- 利于SEO
express官方推荐使用pug模板引擎来实现ssr,所以我们要先下载
npm i pug 或者 yarn add pug
然后要设置pug为默认的渲染视图引擎
app.set('view engine', 'pug')
然后我们在views里面写一个index.pug,输入下面的代码
html
head
title= title
body
h1= message
这是pug模板我有的语法,左边是对应的标签,等号后面是对应的js变量,然后我们在请求的时候把数据传入模板引擎,进行渲染
app.get('/', function (req, res) {
// 参数1是指要去views里面找index.pug
// 参数2是要传入pug里面解析的数据
res.render('index', { title: 'Hey', message: 'Hello there!' })
})
五、数据库
5.1 概念与基本操作
数据库其实只是一个用来管理数据的软件
//数据库的基本操作
/*sql操作
sql 语句
查
select 字段1 , 字段2 ,... from 哪一张数据表
select * from 哪一张数据表
增
insert into 数据表 set key = value ,key = value ,....
改
updata 数据表 set key = value ,key = value ,....
删
delete from 数据表 where id = 1
*/
5.2使用Node操作数据库
//1. 需要一个第三方模块 mysql 模块
// npm init -y(初始化) , npm install mysql -s(下载mysql模块)
// 2.1 引入
import mysql from 'mysql'
// 2.2 创建数据库连接
var connection = mysql.createConnection({
host: '127.0.0.1', // 数据库的地址 ip
port: 3306, // 端口
user: 'root', // 用户信息
password: 'root', // 用户密码
database: 'db_test' //自己mysql的名称 哪一个数据库
});
// 2.3 准备自己的sql语句
const sql = 'select * from student'
// 执行sql语句
connection.query(sql,(err,result,fileds) =>{
// err 错误
// result 执行语句的结果
// fileds 只有执行了select 语句的时候 才会有 ,是 查出来的所有字段内容
if(err) console.log(err);
console.log(result);
})
六、跨域
6.1 基本概念
跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。
同源: 域名相同、协议相同、端口相同.
6.2 jsonp解决跨域
jsonp的原理是复用 src 这种能自带跨域能力的属性进行请求,然后要求服务器把数据放在一个函数调用的格式里面返回,最终我们在前端准备一个函数,进行数据的处理
<script>
// 在前端准备一个函数,用于接收并处理数据
function receive(data){
console.log(data)
}
</script>
// 使用src发起请求,带上前端用于接收数据的函数名
<script src="http://127.0.0.1:8080/jsonp?callback=receive" ></script>
const express = require('expredd')
const app = express()
app.listen(8080)
app.get('/jsonp',(req,res)=>{
// 得到前端用于接收数据的函数名
let {callback} = req.query
let data = JSON.stringiry({code : 200,msg:'ok'})
// 以 函数名(数据) 的形式把数据响应回浏览器
res.send(`${callback}(${data})`)
})
6.3 服务器设置响应头
import express from 'express'
const app = express()
app.listen(8090)
app.get('/constest',(req,res) =>{
// res.setHeader('Access-Control-Allow-Origin','前端的域名')
// res.setHeader('Access-Control-AllowOrigin','http://127.0.0.1:5500')
// res.setHeader('Access-Control-Allow-Origin','*')
// 为保险起见 , 会设置三个响应头
// 设置允许跨域的域名 '*' 代表允许任意域名跨域
res.setHeader("Access-Control-Allow-Origin","*")
// 允许的header类型
res.setHeader("Access-Control-Allow-Headers","Content-Type")
// 允许的请求方式 Methods 方法 研究方法 方式 办法
res.setHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS,PUT")
res.send("OK")
})
6.4 设置代理服务器
6.4.1. 准备一个真正处理请求的服务器
import express from 'express'
const app = express()
app.listen(8080)
// 监听一个get的请求
app.get('/proxydata',(req,res) => {
// 真正在这里去处理xxxxx的数据 ----省略
res.send({code :200,msg:"OK",data})
})
6.4.2 准备一个代理服务器
import http from 'http'
const server = http.createServer()
server.on('request', (req, res) => {
// 在代理服务器下 设置允许跨域
// 设置允许的 域名 *
// 设置允许跨域的域名 '*' 代表允许任意域名跨域
res.setHeader("Access-Control-Allow-Origin", "*")
// 允许的header类型
res.setHeader("Access-Control-Allow-Headers", "Content-Type")
// 允许的请求方式
res.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT")
// 监听浏览器发送的请求
if (req.url === '/proxydemo') {
// 请求真正的数据服务器
http.get('http://127.0.0.1:8080/proxydata', (result) => {
let data = ""
result.on('data', chunk => data += chunk)
result.on('end', () => {
console.log(data);
// 将数据转发给浏览器
res.end(data)
})
})
}
})
server.listen(8081)
6.4.3 html中请求代理服务器
<body>
<button id="btn">发请求</button>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<script>
$("#btn").on('click',function(){
$.ajax({
url:"http://127.0.0.1:8081/proxydemo",
success(res){
console.log(res);
}
})
})
</script>
</body>