# Nodejs服务端
# 一、http模块
//引入http模块
const http = require('http');
//创建http服务
http.createServer((request, response) => {
console.log(request.url)//获取url
//设置响应头
response.writeHead(200, { 'Content-Type': 'text/plain;charset="utf-8"' })
//结束响应并返回给客户端
response.end('Hello 哈哈哈')
}).listen(8039, () => console.log('Server running at http://localhost:8039/'))
//监听端口为8039
# 二、url模块
var url = require('url')
//默认第二个参数为false(query属性不转换成json)
console.log(url.parse('http://user:pass@sub.host.com:8080/p/a/t/h?skip=0&limit=10#hash'))
Url {
protocol: 'http:',//传输协议
slashes: true,//slashes指的是 如果 protocol 协议冒号后面跟着两个 ASCII 斜杠字符(/)
auth: 'user:pass',//作者
host: 'sub.host.com:8080',//host 比 hostname多端口
port: '8080',//端口号
hostname: 'sub.host.com',
hash: '#hash',//hash锚点
search: '?skip=0&limit=10',//search比query多?
query: 'skip=0&limit=10',//当第二个参数为true时,query属性值为一个参数对象
pathname: '/p/a/t/h',//path比pathname多后面参数
path: '/p/a/t/h?skip=0&limit=10',
href: 'http://user:pass@sub.host.com:8080/p/a/t/h?skip=0&limit=10#hash',//href是完整路径
}
//第二个参数为true(query属性转换成json)
console.log(url.parse('http://user:pass@sub.host.com:8080/p/a/t/h?skip=0&limit=10#hash',true))
Url {
protocol: 'http:',
slashes: true,
auth: 'user:pass',
host: 'sub.host.com:8080',
port: '8080',
hostname: 'sub.host.com',
hash: '#hash',
search: '?skip=0&limit=10',
query: [Object: null prototype] { skip: '0', limit: '10' },
pathname: '/p/a/t/h',
path: '/p/a/t/h?skip=0&limit=10',
href: 'http://user:pass@sub.host.com:8080/p/a/t/h?skip=0&limit=10#hash'
}
# 三、fs模块
# 1】fs.stat
检测是文件还是目录
var fs = require('fs')
fs.stat('./html',(err,data)=>{
if(err){
console.log(err);
return;
}
console.log(`是文件:${data.isFile()}`)
console.log(`是目录:${data.isDirectory()}`)
})
# 2】fs.mkdir
创建目录
fs.mkdir(path,[mode],[callback])
- Path:将创建的目录路径
- Mode:目录权限(读写权限),默认777
- Callback:回调,传递异常参数err
var fs = require('fs')
fs.mkdir('./css',err=>{
if(err){
console.log(err);
return;
}
console.log('创建成功')
})
# 3】fs.writeFile
创建文件并写入内容(或替换文件并写入内容)
fs.writeFile(filename,data,[option],[callback]
- Filename:(String)文件名称
- Data:(String|Buffer)将要写入的内容
- Option:(Object)option数组对象包含:
- Encoding:(String)默认
utf8
,当data使buffer时,该值应该为ignored
。 - Mode:(Number)文件读写权限,默认值为
438
- Flag:(String)默认值为
'w'
- Encoding:(String)默认
var fs = require('fs')
fs.writeFile('./index.txt','你好',err=>{
if(err){
console.log(err);
return;
}
console.log('创建并写入文件成功')
})
# 4】fs.appendFile
文件追加内容
var fs = require('fs')
fs.appendFile('./index.txt','你好',err=>{
if(err){
console.log(err);
return;
}
console.log('文件追加内容成功')
})
# 5】fs.readFile
读取文件内容
var fs = require('fs')
fs.readFile('./index.txt',(err,data:Buffer)=>{
if(err){
console.log(err);
return;
}
console.log('读取的内容是:',data)//默认是读取到十六进制的buffer类型
console.log(data.toString())//Buffer转成String类型
})
# 6】fs.readdir
读取目录(将所以的文件名或目录名存在数组中)
var fs = require('fs')
fs.readdir('./',(err,data:Array)=>{
if(err){
console.log(err);
return;
}
console.log(data)//['fliename1.html','js','filename2.css']
})
# 7】fs.rename
1.重命名文件或目录 2.移动文件或目录
var fs = require('fs')
fs.rename('./css/aaa.css','./css/index.css',err=>{
if(err){
console.log(err);
return;
}
console.log('文件重命名成功')
})
fs.rename('./css/aaa.css','./html/index.css',err=>{
if(err){
console.log(err);
return;
}
console.log('文件移动成功')
})
# 8】fs.rmdir
删除目录
var fs = require('fs')
fs.rmdir('./css',err=>{
if(err){
console.log(err);
return;
}
console.log('删除目录成功')
})
# 9】fs.unlink
var fs = require('fs')
fs.unlink('./css/aaa.css',err=>{
if(err){
console.log(err);
return;
}
console.log('删除文件成功')
})
# 四、路由
针对不同的请求的URL,处理不同的业务逻辑。
# 1】原生nodejs模块化封装接口和静态服务:
使用中间件 router[name](req, res)
的方式调用
//router.js路由配置文件
const url = require('url')
const fs = require('fs')
const app = {
//静态服务
static: (req, res, static_path) => {
const path = url.parse(req.url).pathname
path_name = path === '/' ? '/index.html' : path
if (path_name !== '/favicon.ico') {
try {//可设置服务器的静态文件目录
const data = fs.readFileSync('./' + static_path + path_name)
if (data) {
res.end(data)
}
} catch (error) {
console.error(error)
}
}
},
login: (req, res) => {
//登录接口
res.end('login')
},
new: (req, res) => {
//新建接口
res.end('new')
},
notFound: (req, res) => {
//404接口
res.end('API 404 ERROR !!!')
}
}
module.exports = app
服务入口文件:
//index.js文件
const http = require('http');
const url = require('url')
const router = require('./router')
http.createServer((req, res) => {
router.static(req, res, 'static');
const path_name = url.parse(req.url).pathname.replace('/', '')
try {
router[path_name](req, res)
} catch (error) {
router['notFound'](req, res)
}
}).listen(8039,
() => console.log('Server running at http://localhost:8039/'))
# 2】封装express的路由
启动服务时通过键值对象的形式注册路由,当前端请求到后端时去表中匹配路由执行不同业务逻辑。
//router.js路由中间件配置文件router.js
const url = require('url')
const path = require('path')
const fs = require('fs')
const server = () => {//将路由放在局部作用域中
const GLOBAL = {
//把get和post的路由分开存
_get: {},
_post: {},
_static: 'static',//如果不指定默认静态目录
}
const app = (req, res) => {
//初始化配置静态目录(首先在静态目录上找url对应的东西,如果没有再走接口逻辑)
initStatic(req, res, GLOBAL._static);
//拓展res的方法
expandRes(res)
//获取请求的pathname
const path_name = url.parse(req.url).pathname
//获取请求类型
const method = req.method.toLowerCase()
if (GLOBAL['_' + method][path_name]) {//判断是否存在
if (method === 'get') {
GLOBAL._get[path_name](req, res)//执行
}
if (method === 'post') {
//接收post传值,把它绑定到req.body
let postData = ''
req.on('data', (chunk) => {
postData += chunk
})
req.on('end', () => {
//将接收到的请求数据存放在req.body里
req.body = postData
GLOBAL._post[path_name](req, res)//执行
})
}
} else {
res.writeHead(404, { 'Content-type': 'text/plain;charset="utf-8"' })
res.end('页面不存在')
}
}
app.get = (api, callback) => {
//注册方法
GLOBAL._get[api] = callback
}
app.post = (api, callback) => {
//注册方法
GLOBAL._post[api] = callback
}
app.static = (_static) => {
//静态web服务
GLOBAL._static = _static
}
return app
}
//拓展res
const expandRes = (res) => {
//封装res.send函数(设置响应头和响应数据)
res.send = (data, config) => {
if (config) {
const status = config['status']
delete config['status']
res.writeHead(status, { ...config })
} else {
res.writeHead(200, { 'Content-type': 'text/plain;charset="utf-8"' })
}
res.end(data)
}
}
//静态web服务中间件
const initStatic = (req, res, static_path) => {
//获取地址
let path_name = url.parse(req.url).pathname
path_name = path_name === '/' ? '/index.html' : path_name
//如果请求的url有后缀名
let ext_name = path.extname(path_name)
//通过fs模块读取文件
try {
let data = fs.readFileSync('./' + static_path + path_name)
if (data) {//如果在静态目录上找到相应的文件,则去匹配对应的Content-type,设置响应头并返回结果
let contentType = getContentType(ext_name)
res.writeHead(200, { 'Content-type': '' + contentType + ';charset=utf-8' })
res.end(data)
}
} catch (error) {
}
}
const getContentType = (extname) => {//去字典中查不同后缀名文件对应的content-type值
let data = fs.readFileSync('./utils/ContentType.json')
let CONTENT_TYPE_MAP = JSON.parse(data.toString())
return CONTENT_TYPE_MAP[extname]
}
module.exports = server()//导出app
这里随便写了一个分页的数据接口:
//index.js入口文件
const http = require('http');
const url = require('url')
const app = require('./router')//封装的express路由
const data = require('./const')//静态数据
http.createServer(app).listen(8039, () => console.log('Server running at http://localhost:8039/'))
app.static('public')//修改静态路由
//事件循环,首先执行同步代码,去注册路由
app.get('/list', (req, res) => {
const query = url.parse(req.url, true).query
const page_size = parseInt(query.page_size)
const page = parseInt(query.page)
const result = { data: data.data.slice((page - 1) * page_size, page * page_size), total: data.total }
res.send(JSON.stringify(result), {
status: 200,
'content-type': 'application/json; charset=utf-8',
'Access-Control-Allow-Credentials': 'true',//配置cors跨域
'Access-Control-Allow-Origin': '*',//配置cors跨域
})
})
app.get('/', (req, res) => {
res.send('first index')
})
app.post('/doLogin', (req, res) => {
res.send(req.body)
})
//const.js任意的数据
const res = {
data: [
{
id: '1',
question: '为什么下架?',
hit_standard_q: '商品下架',
utterance: [
{
text: '哈哈哈哈哈哈,我知道了哦亲',
role: 1,
ms_time: '2020-12-15 19:12:33',
is_badcase: false,
}
],
},
]
, total: 1
}
module.exports = res