Node.JS 模块化
1、require 导入模块
const http=require('http')
2、exports 导出模块
db={name:'jine',age:22}
module.exports=db
内置模块使用
1、导包
const fs=require('fs');
2、调用unlink删除文件方法
fs.unlink('./tmp/hello.txt',(err)=>{
if(err) throw err;
console.log('已成功删除 /tmmp/hello')
})
-----------------------------------------------------------------------------------------
文件读取操作,例如
const fs=require('fs')
fs.readFile('./etc/passwd.txt','utf-8',(err,data)=>{
console.log(err);
//err是一个错误对象,没有就返回一个null
console.log(data);
})
-----------------------------------------------------------------------------------------
文件写操作(如果没有文件会创建一个,若有会覆盖掉),例如:
const fs=require('fs')
const data=`
我是一段文本内容,啦啦啦啦啦啦啦啦啦啦啦~~~
`
fs.writeFile('./etc/content.txt',data,(err)=>{
if(err==null){
console.log("文件保存成功√")
}else{
console.log(err)
}
})
获取文件或目录的路径
console.log(__dirname)
/*获取的是当前文件的所在目录的绝对路径 */
console.log(__filename)
/*获取的是当前文件的绝对路径*/
path 模块
为了避免少些斜杠而导致路径不对,可以引入path模块
const path=require('path')
const filePath=path.join(__dirname,'test','file.txt')
console.log(filePath)
/*
c:\Users\Jine\Desktop\my_code_space\jine\Daily code practice\07、03\test\file.txt
*/
http 模块
//使用内置模块http创建一个服务器
//1、导入http模块
const http=require('http')
//2、创建一个服务器 (返回值代表当前服务器)
const server=http.createServer((request,response)=>{
//3、设置返回给用户看的内容
response.setHeader('Content-Type','text/html;charset=utf-8')
/*setHeader 防止中文乱码,所以要设置响应头 */
response.end("你好,世界~")
})
//4、开启服务器
server.listen(1024,()=>{
console.log("服务器开启~")
})
/*开启服务器后,可以在本地浏览器中访问 127.0.0.1:1024 或 localhost:1024*/
静态资源服务器
//导入模块
const http=require("http")
const fs=require("fs")
const path=require('path')
//创建服务器
const server=http.createServer((request,response)=>{
//设置返回用户内容
//获取用户请求哪一个资源
let userRq=request.url
//获取用户读取的资源对应的路径
const filePath=path.join(__dirname,'web',userRq)
//读取用户请求的资源文件
fs.readFile(filePath,(err,data)=>{
if(err==null){
response.end(data)
}else{
response.end("404 not found")
}
})
})
server.listen(8888,()=>{
console.log("服务器开启成功√")
})
URL 模块 (get)
"get 应用(数据存在url中,相对较小,req.url可以拿到)"
"get 安全性低,一般用于请求数据/获取数据
例如:
//导入模块
const http=require('http')
const url=require('url')
//创建服务器
const server=http.createServer((request,response)=>{
/*通过request.url拿到前端传递过来的参数
* 导入url模块,处理接受到的字符串
* 调用parse方法,(参数1:要处理的url,参数2:如果写true便返回一个对象)
* 返回的对象中有query属性,其也是一个对象,这个属性里面有get传递过来的参数
*/
let URL=url.parse(request.url,true)
// console.log(URL.query)
response.end(JSON.stringify(URL.query))
/*若拿到了get信息对应的数据,便可返回字符串给前端 */
})
//启动服务器
server.listen(8888,()=>{
console.log("服务器已开启√")
})
querystring 模块(post)
"post 应用(数据存在请求体中,相对而言较大,传递到node.js会分小块传送)"
"post 一般用于提交数据"
"测试post接口软件 https://www.postman.com/downloads/"
node.js如何接收:
他也是一小块一小块的接收.
1.首先有一个容器
2.给req对象一个data事件(这个事件会执行很多次)这个事件里面就把这些小块的数据拼接起来
3.给req对象一个end事件(这个事件只会执行一次)表示数据传递完了
4.处理传递过来的数据转为对象 queryString.parse();
例如:
//导入模块
const http=require('http')
const querystring=require('querystring')
//创建服务器
const server=http.createServer((request,response)=>{
//容器
let postData=""
//给request对象一个data事件
//事件处理程序,chunk参数是这次传递过来的一小块内容
request.on('data',(chunk)=>{
//将每此传过来小块的内容放到容器中
postData+=chunk
})
//数据传递完毕执行
request.on('end',()=>{
//打印容器
console.log(postData)
//解析容器中的数据,转为对象
let postObj=querystring.parse(postData)
console.log(postObj)
})
//可以根据post传来的参数,去数据库中判断是否正确
//最后返回前端页面
response.end("over")
})
//启动服务器
server.listen(8888,()=>{
console.log("服务器已开启√")
})
第三方模块
爬虫模块
1、新建文件夹,文件夹名字非中文,且不要和模块名一样
2、在cmd打开这个文件夹,然后输入 npm init -y (初始化)
3、去npm官网,搜索crawler
4、在cmd中运行 npm i crawler(下载爬虫模块)
5、使用爬虫,如下代码
爬取元素内容,例如:
var Crawler = require("crawler");
var c = new Crawler({
maxConnections : 10,
// This will be called for each crawled page
callback : function (error, res, done) {
if(error){
console.log(error);
}else{
var $ = res.$;
// $ is Cheerio by default
//a lean implementation of core jQuery designed specifically for the server
console.log($("title").text());
}
done();
}
});
// Queue just one URL, with default callback
c.queue('http://www.baidu.com');
-----------------------------------------------------------------------------------------
爬取图片或视频,例如:
var Crawler = require("crawler");
var fs = require('fs');
var c = new Crawler({
encoding:null,
jQuery:false,// set false to suppress warning message.
callback:function(err, res, done){
if(err){
console.error(err.stack);
}else{
fs.createWriteStream(res.options.filename).write(res.body);
}
done();
}
});
c.queue({
uri:"https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=false&word=%E7%BE%8E%E5%A5%B3&step_word=&hs=0&pn=7&spn=0&di=35090&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=0&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=undefined&cs=3186997546%2C1762170182&os=86097226%2C93959096&simid=3448572432%2C288122016&adpicid=0&lpn=0&ln=3390&fr=&fmq=1593780721779_R&fm=&ic=undefined&s=undefined&hd=undefined&latest=undefined©right=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&ist=&jit=&cg=girl&bdtype=0&oriquery=&objurl=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201309%2F03%2F20130903141830_Q4Wuc.jpeg&fromurl=ippr_z2C%24qAzdH3FAzdH3F4_z%26e3B17tpwg2_z%26e3Bv54AzdH3Frj5rsjAzdH3F4ks52AzdH3F8bnmndnllAzdH3F1jpwtsAzdH3F&gsm=7&rpstart=0&rpnum=0&islist=&querylist=&force=undefined",
filename:"./mv.jpg",
headers:{'User-Agent':'requests'}
/*让服务器伪装成客户端,这样可以破解防爬虫 */
});
自动重启工具(nodemon)
在编写调试Node.js项目,修改代码后,需要频繁的手动close掉,然后再重新启动,非常繁琐。现在,我们可以使用nodemon这个工具,它的作用是监听代码文件的变动,当代码改变之后,自动重启。
例如:
nodemon app.js
package.json 和 package-lock.json
package.json
默认项目初始化json文件,用来描述项目的信息
1.使用npm5之前的版本,是不会生成package-lock json这个文件的。
2. npm5以后,包括npm5这个版本,才会生成package-lockjson文件
3.当使用npm安装包的时候,npm都会生成或者更新package-lock.json文件。
npm5以后的版本,在安装包的时候,不需要加--save (-S) 参数, 也会自动在package.json中保存依赖项(依赖包)。
当安装包的时候,会自动创建或者更新package-lock json文件。
package-lock.json文件内保存了node_ _modules中所有包的信息,包含这些包的名称、版本号、下载地址。
带来好处是,如果重新npm install的时候,就无需逐个分析包的依赖项,因此会大大加快安装速度。
从package-lock.json文件名来看,lock代表的是“锁定”的意思。
它用来锁定当前开发使用的版本号,防止npm instal的时候自动更新到了更新版本。
因为新版本有可能会更新老的api,导致之前的代码出错。
原来的package.json文件只能锁定大版本,也就是版本号的第一位,并不能锁定后面的小版本,你每次npm install
都是拉取的该大版本下的最新的版本,为了稳定性考虑我们几乎是不敢随意升级依赖包的,这将导致多出来很多工
作量,测试/适配等,所以package-lock.jison文件出来了,当你每次安装一个依赖的时候就锁定在你安装的这个版本
express 模块
1、安装前,先清空缓存,否则会报错。 (npm cache clean -f)
2、安装(npm i express)
使用如下,例如:
//导入模块
const express = require('express')
//调用express()方法创建服务器
const app = express()
//设置返回用户看的内容
app.get('/', function (req, res) {
//若用内置模块http创建的服务器,返回内容用res.end() 响应
//此express模块创建的服务器,用res.send() 响应
//使用express模块返回中文时不用给响应头中加中文转义,默认会转义
res.send(`<h1>Hello World~</h1>
<p>你好呀</p>
`)
})
//开启服务器
app.listen(8888,()=>{
console.log("服务器开启成功√")
})
创建静态资源服务器
访问express中文网的静态文件的创建(https://www.expressjs.com.cn/starter/static-files.html)
例如:
//导入模块
const express = require('express')
//调用express()方法创建服务器
const app = express()
//通过如下代码,便可将web目录下的图片、css文件、JavaScript文件对外开放访问
app.use(express.static('web'))
//开启服务器
app.listen(8888,()=>{
console.log("服务器开启成功√")
})
实现简单的get 接口
/**
* 接口:得到一条随机笑话
* 接口地址:/joke
* 请求方式:get
* 参数:无
* 返回:一条笑话
*/
//导包
const express = require('express')
//创建服务器
const app = express()
//写接口
app.get('/joke',(req,res)=>{
//实际开发是从数据库或其他数据源获取
let arr=['世界是你的','程序员会找到女朋友','你的代码永不报错']
let index=Math.floor(Math.random()*3); //0,1,2
//返回笑话
res.send(`<h1>${arr[index]}</h1>`)
})
//开启服务器
app.listen(8888,()=>{
console.log("服务器已开启√")
})
实现带有参数的get接口
/**
* 接口:查询英雄对应的外号
* 接口地址:/name
* 请求方式:get
* 参数:heroName
* 返回:英雄外号
*/
//导包
const express = require('express')
//创建服务器
const app = express()
//写接口
app.get('/name',(req,res)=>{
//要接受前端,传递过来的参数
let hero=''
//req.query返回的是一个对象
//herName便是get请求的参数
switch(req.query.heroName){
case '提莫':
hero='迅捷斥候'
break;
case '李青':
hero="盲僧"
break;
case '阿狸':
hero="九尾妖狐"
break;
case '猴子':
hero="齐天大圣"
break;
default:
hero="该英雄查询不到";
break;
}
res.send(`<h1 style=color:red;>${hero}</h1>`)
})
//开启服务器
app.listen(8888,()=>{
console.log("服务器已开启√")
})
实现返回json数据的接口
/**
* 接口:返回一个食物
* 接口地址:/food
* 请求方式:get
* 请求参数:无
* 返回值:json
*/
//导包
const express = require('express')
//创建服务器
const app = express()
//写接口
app.get('/food',(req,res)=>{
//1、express模块写法:直接写成对象,这样会自动返回json格式
res.send({
foodName:'宫保鸡丁',
price:22,
description:'肉大,菜香,多吃不腻'
})
// //2、原生内置模块写法:使用内置模块setHeader设置
// res.setHeader('Conten-Type','application/json');
// res.send(`
// foodName:'宫保鸡丁',
// price:22,
// description:'肉大,菜香,多吃不腻'
// `)
})
//开启服务器
app.listen(8888,()=>{
console.log("服务器已开启√")
})
实现简单的post 接口
/**
* 接口:返回默认字符串
* 接口地址:/str
* 请求方式:post
* 参数:无
* 返回:这是一个post接口
*/
//导包
const express = require('express')
//创建服务器
const app = express()
//写接口
app.post('/str',(req,res)=>{
res.send(`<h1>这是一个post接口</h1>`)
})
//开启服务器
app.listen(8888,()=>{
console.log("服务器已开启√")
})
实现带有参数的post接口
导入第三方模块(npm i body-parser)
/**
* 接口:用户登录
* 接口地址:/login
* 请求方式:post
* 参数:username password
* 返回:登录成功/登录失败
*/
//需要使用第三方模块body-parser获取post传递的过来的参数
//安装模块(npm i body-parser)
//导包
const express = require('express')
const bodyParser=require('body-parser')
//创建服务器
const app = express()
//parse application/ x-www-form-urlencoded
//将post请求体中的格式转换为urlencoded格式
app.use(bodyParser.urlencoded({extended:false}))
//写接口
app.post('/login',(req,res)=>{
//实际开发根据数据库中的数据进行判断
//req.body 返回的是post对象,username和password是自定义的参数
if(req.body.username=='admin' && req.body.password=='88888888'){
res.send({
code:200,
msg:"登录成功"
})
}else{
res.send({
code:400,
msg:'账户密码不正确'
})
}
})
//开启服务器
app.listen(8888,()=>{
console.log("服务器已开启√")
})
实现post方式传文本参数的接口
导入第三方模块(npm i multer)
/**
* 接口:用户登录
* 接口地址:/register
* 请求方式:post
* 参数:username password usericon(用户头像/图片文件)
* 返回:注册成功/注册失败
*/
//需要使用第三方模块multer接受post传递过来的文本参数
//安装模块(npm i multerr)
//导包
const express = require('express')
const multer=require('multer')
//用包:创建一个uploads文件夹,接受传递来的文本
let upload=multer({dest:'uploads/'})
//创建服务器
const app = express()
//写接口
app.post('/register',upload.single('usericon'),(req,res,next)=>{
// req.file is the usericon file
//传过来的文件参数名用usericon
// req. body will hold the text fields, if there were any
//一起传过来的文件保存在req.body中
//记录了传递过来的文件的一些信息
console.log(req.file)
//记录了传递过来的post对象和其中的参数
console.log(req.body)
})
//开启服务器
app.listen(8888,()=>{
console.log("服务器已开启√")
})
注册路由
后端路由
注册路由:说白了就是写接口(API)
将多个接口放入一个文件中,只开启一次服务器
例如:
//后端路由
//注册路由:说白了就是写接口(API)
//导包
const express = require('express')
//创建服务器
const app = express()
//注册路由
//1、注册接口
app.post('/register',(req,res)=>{
//逻辑...
res.send("注册成功")
})
//2、登录接口
app.post('/login',(req,res)=>{
//逻辑...
res.send("登录成功")
})
//3、获取所有英雄接口
app.get('/getAllHero',(req,res)=>{
//逻辑...
res.send("获取成功")
})
自定义模块
自定义模块(文件名为:'自定义模块.js'),如下:
let db={
name:'jine',
age:'22',
fun(){
console.log("我是一个方法")
},
funny(){
console.log('我也是一个方法~~')
}
}
//导出,提供接口
module.exports=db
-----------------------------------------------------
这样便可以使用我们自定义的模块如下:
//导包
const myMoudle=require('./自定义模块.js')
console.log(myMoudle.name)
console.log(myMoudle.age)
myMoudle.fun()
myMoudle.funny()
其他补充
服务器重定向
服务器主动修改浏览器地址栏
//导包
const express=require("express")
//创建服务器
const app=express()
//如果访问本服务器中找不到输入的这个页面,就会自动重定向跳转到指定页面
app.use((req,res)=>{
//设置302响应头
//结束响应
res.writeHead(302,{
Location:'https://blog.3xnb.com'
});
res.end("ok")
})
//启动服务器
app.listen(8888,()=>{
console.log("服务器已开启√")
})
中间件
服务器开启之后和路由器响应之前执行的一个函数
这个函数可以操作req,res
next() 执行下一个中间件
例如:
//导包
const express=require("express")
const bodyParser=require("body-parser")
//创建服务器
const app=express()
//中间件
//服务器开启之后和路由器响应之前执行的一个函数
//这个函数可以操作req,res
//next() 执行下一个中间件
app.use((req,res,next)=>{
console.log("LOGGED")
next()
})
//API
app.get('/hello',(req,res)=>{
res.end("Hello World~")
})
//启动服务器
app.listen(8888,()=>{
console.log("服务器已开启√")
})
跨域
报错类型:'Access-Contril-Allow-Origin'
-----------------------------------------------------------------------------------------
什么是跨域?
浏览器使用ajax时,如果请求的接口地址和当前打开页面的地址不同源称之为跨域
同源:协议,地址,端口都相同(反之有一个不满足就为不同源)
-----------------------------------------------------------------------------------------
出于安全考虑,浏览器不允许,页面向不同源的接口请求数据,因为如果接口和网页不同源,浏览器默认认为是俩个不同的服务器。
解决跨域
跨域是前端工作中不可避免的问题:我们经常会出现请求不同源接口的情况,为了能够获取数据,解决跨域的问题方案也有很多,但是常用的就两种
■第一种: CORS(后端操作)
目前的主流方案,也是最简单的方案,直接让后端设置响应头,允许资源共享就ok.
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
例如:
app.get('/login',(req,res)=>{
//设置响应头,允许资源被访问/共享
res.setHeader('Access-Control-Allow-Origin','*')
/*表示所有请求路径都可以请求这个接口*/
})
解决跨域问题,设置响应头的代码,可以在中间件中写,这样可以在所有接口中都会应用到(只在中间件写一次就可以了,不用再多个接口中去写,因为中间件是在服务器开启之后和路由响应之前执行的一个函数)
例如:
app.use((req,res,next)=>{
//在中间件中设置响应头,允许资源被所有接口访问/共享
res.setHeader('Access-Control-Allow-Origin','*')
next()
})
-----------------------------------------------------------------------------------------
或者还可以安装第三方模块(npm i cors)
例如:
//导入包
const cors=require('cors')
//使用
app.use(cors());
/*直接使用这个模块,便可省略在中间件中写的解决跨域问题的代码*/
■第二种:JSONP(前后端配合)
曾经的跨域杀手,专治各种跨域问题。现在慢慢的淡出历史舞台
PS:面试官特别喜欢问这个,因为这个有一定的技术难度,也能体现一个人的实际开发经验
jsonp是前后端来配合使用的.
使用原理:通过动态创建script标签通过script标签的src请求没有跨域限制来获取资源
补充知识:
浏览器页面上使用ajax发请求,当前页面地址和ajax请求的地址不同源,才会有跨域限制
但script、img、link标签中的src属性发的请求都没有跨域限制
使用jsonp原理:
这样便可以用script标签中的src来操作,去访问后端地址的接口时,前后端规定好使用的get请求传入的参数名便可,这样也没有了跨域限制
-----------------------------------------------------------------------------------------
前端页面,例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSONP</title>
</head>
<body>
<script>
function print(obj){
alert(obj.user)
alert(obj.data)
}
</script>
<!-- 前端页面:访问后端API,传入后端指定get参数,后端处理返回后,接受到返回的调用和实参对象来使用 -->
<script src="http://127.0.0.1:8888/getAll?fun=print"></script>
</body>
</html>
-----------------------------------------------------------------------------------------
后端页面,例如:
//导包
const express=require("express")
//创建服务器
const app=express()
app.get('/getAll',(req,res)=>{
//接受到前端传入的get参数,当作函数调用这个参数,并传入实参对象,最后返回前端
res.send(`${req.query.fun}({"user":"我是jine","data":"成功调用√"})`)
})
//启用服务器
app.listen(8888,()=>{
console.log("服务器成功启动√")
})
-----------------------------------------------------------------------------------------
或者还可以直接在Ajax请求时,加上 dataType:'jsonp'
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>点击哟</title>
<script src="https://jine.oss-cn-beijing.aliyuncs.com/API/jquery-3.5.0.js"></script>
<script>
$(()=>{
let $btn= $('button')
$btn.on("click",()=>{
$.ajax({
url:'http://127.0.0.1:8888/getAll',
dataType:'jsonp',
success:(backData)=>{
alert(backData.user)
alert(backData.data)
}
})
// 如果访问的接口支持jsonp,那么发送ajax便可以使用jsonp
// ajax加 dataType:'jsonp' 便可使用
// 加的原理是:自动创建一个script标签,用他的src属性去请求服务器
//注意:后端中的参数必须是callback,因为使用ajax开启jsonp,src传递的参数是callback,所以要一致
})
})
</script>
</head>
<body>
<button>点击我哟~</button>
</body>
</html>
"注意:后端中的参数必须是callback,因为使用ajax开启jsonp,src传递的参数是callback,所以要一致"
聚合数据(API)
百度搜索聚合数据,进入官方
便可调用别人提供已经写好的API
只要使用的接口支持jsonp,那么可以用ajax去请求