1.url概念、组成
url:统一资源定位符
┌─────────────────────────────────────────────────────────────────────────────────────────────┐
│ href │
├──────────┬──┬─────────────────────┬─────────────────────┬───────────────────────────┬───────┤
│ protocol │ │ auth │ host │ path │ hash │
│ │ │ ├──────────────┬──────┼──────────┬────────────────┤ │
│ │ │ │ hostname │ port │ pathname │ search │ │
│ │ │ │ │ │ ├─┬──────────────┤ │
│ │ │ │ │ │ │ │ query │ │
" https: // user : pass @ sub.host.com : 8080 /p/a/t/h ? query=string #hash "
│ │ │ │ │ hostname │ port │ │ │ │
│ │ │ │ ├──────────────┴──────┤ │ │ │
│ protocol │ │ username │ password │ host │ │ │ │
├──────────┴──┼──────────┴──────────┼─────────────────────┤ │ │ │
│ origin │ │ origin │ pathname │ search │ hash │
├─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────────┴───────┤
│ href │
└─────────────────────────────────────────────────────────────────────────────────────────────┘
1.node常用的内置模块
- URL 网址解析,解析URL相关网址信息
url.parse(urlString,options)
- url.format(urlObject)
- url.resolve(from, to)
方法一:将一个url地址变成一个对象
url.parse(urlString,options);
第一个参数填的是一个ulr地址
第二个参数默认是false,如果你设置成true,那就可以将上图中url组成的query转成对象的形式
//url模块讲解
var url=require('url');
var str='http://www.alibaba.com:4000/api/home/a?key=hello&token=124#banner'
var obj=url.parse(str,true);
// 如果第二个参数为true,就表示,把url的query解析成对象形式。
console.log(obj);
/*
obj.protocal 协议 http:
obj.host 域 www.alibaba.com:4000
obj.hostname 域名 www.alibaba.com
obj.port 端口号 4000
obj.hash 哈希 #banner
obj.query: 参数: key=hello&token=124 或者 {key:'hello',token:124}
obj.pathname : 路径 /api/home/a
*/
方法二:将对象(格式正确)转化成一个url地址
url.format(URL,options)
options -->{ }
auth 如果序列化的URL字符串应该包含用户名和密码为true,否则为false。默认为true。
fragment 如果序列化的URL字符串应该包含分段为true,否则为false。默认为true。
search 如果序列化的URL字符串应该包含搜索查询为true,否则为false。默认为true。
unicode true 如果出现在URL字符串主机元素里的Unicode字符应该被直接编码而不是使用Punycode编码为true,默认为false。
new URL('https://a:b@你好你好?abc#foo')
返回一个URL对象
虽然URL对象的toString()
方法和href
属性都可以返回URL的序列化的字符串。然而,两者都不可以被自定义。而url.format(URL, options)方法允许输出的基本自定义。
const { URL } = require('url');
const myURL = new URL('https://a:b@你好你好?abc#foo');
console.log(myURL.href);
// 输出 https://a:b@xn--6qqa088eba/?abc#foo
console.log(myURL.toString());
// 输出 https://a:b@xn--6qqa088eba/?abc#foo
console.log(url.format(myURL, { fragment: false, unicode: true, auth: false }));
// 输出 'https://你好你好/?abc'
方法三 为URL或 href 插入 或 替换原有的标签
url.resolve(from, to)
接收参数:
from 源地址
to 需要添加或替换的标签
var url = require('url');
var a = url.resolve('/one/two/three', 'four') ,
b = url.resolve('http://example.com/', '/one'),
c = url.resolve('http://example.com/one', '/two');
console.log(a +","+ b +","+ c);
//输出结果:
///one/two/four
//http://example.com/one
//http://example.com/two
-
fs 文件模块
文件写入
Node中文件读取的方式主要有:fs.readFile(file[, options], callback(error, data))
fs.readFile('c:\\demo\1.txt', 'utf8', (err, data) => { if (err) throw err; console.log(data); });
fs.readFileSync(file[, options])
try { const data = fs.readFileSync('c:\\demo\1.txt', 'utf8'); console.log(data); } catch(e) { // 文件不存在,或者权限错误 throw e; }
- fs.createReadStream(path[, options])
const stream = fs.createReadStream('c:\\demo\1.txt'); let data = '' stream.on('data', (trunk) => { data += trunk; }); stream.on('end', () => { console.log(data); });
文件写入
Node中文件写入的方式主要有:- fs.writeFile(file, data[, options], callback(error))
fs.writeFile('c:\\demo\a.txt', new Date(), (error) => { console.log(error); });
- fs.writeFileSync(file, data[, options])
try { fs.writeFileSync('c:\\demo\a.txt', new Date()); } catch (error) { // 文件夹不存在,或者权限错误 console.log(error); }
- fs.createWriteStream(path[,option])
var streamWriter = fs.createWriteStream('c:\\demo\a.txt'); setInterval(() => { streamWriter.write(`${new Date}\n`, (error) => { console.log(error); }); }, 1000);
-
path模块
- path.basename(path[, ext])
- path路径
- ext可选的文件扩展名
- path.basename() 方法返回一个 path 的最后一部分
path.basename('/foo/bar/baz/asdf/quux.html'); // 返回: 'quux.html' path.basename('/foo/bar/baz/asdf/quux.html', '.html'); // 返回: 'quux'
-
path.dirname(path)
- path.dirname() 方法返回一个 path 的目录名
path.dirname('/foo/bar/baz/asdf/quux'); // 返回: '/foo/bar/baz/asdf'
如果 path 不是一个字符串,则抛出 TypeError。
注意:只能返回目录名,并不能返回目录的详细信息
-
path.extname(path)
path.extname() 方法返回 path 的扩展名path.extname('index.html'); // 返回: '.html' path.extname('index.coffee.md'); // 返回: '.md' path.extname('index.'); // 返回: '.' path.extname('index'); // 返回: '' path.extname('.index'); // 返回: ''
-
path.join([...paths])
path.join() 方法使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径。path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); // 返回: '/foo/bar/baz/asdf' path.join('foo', {}, 'bar'); // 抛出 'TypeError: Path must be a string. Received {}'
-
path.normalize(path)
path.normalize() 方法会规范化给定的 path,并解析 ‘…’ 和 ‘.’ 片段 -
path.parse(path)
path.parse() 方法返回一个对象,对象的属性表示 path 的元素。 尾部文件分隔符会被忽略
返回的对象有以下属性
dir
root
base
name
extpath.parse('C:\\path\\dir\\file.txt'); // 返回: // { root: 'C:\\', // dir: 'C:\\path\\dir', // base: 'file.txt', // ext: '.txt', // name: 'file' }
- path.basename(path[, ext])
-
QueryString 参数处理
- querystring.escape(str)
- querystring.unescape(str)
querystring.parse(str[, sep[, eq[, options]]])
- querystring.stringify(obj[, sep[, eq[, options]]])
queryString用于解析与格式化 URL 查询字符串
方法一:querystring.escape(str)
对给定的 str 进行 URL 编码。
方法二:querystring.unescape(str)
对给定的 str 进行 URL 解码。
方法三:querystring.stringify(obj[, sep[, eq[, options]]])
将对象转化成字符串
sep 第二个参数 用于界定查询字符串中的键值对的子字符串。默认为 ‘&’。
eq 第三个参数 用于界定查询字符串中的键与值的子字符串。默认为 ‘=’。
options
encodeURIComponent 把对象中的字符转换成查询字符串时使用的函数。默认为 querystring.escape()。该方法通过遍历给定的 obj 对象的自身属性,生成 URL 查询字符串。
// 假设存在 gbkEncodeURIComponent 函数。
querystring.stringify({ w: '中文', foo: 'bar' }, null, null,
{ encodeURIComponent: gbkEncodeURIComponent });
方法四:querystring.parse(str[, sep[, eq[, options]]])
将query字符串装华为对象
sep 第二个参数 用于界定查询字符串中的键值对的子字符串。默认为 ‘&’。
eq 第三个参数 用于界定查询字符串中的键与值的子字符串。默认为 ‘=’。
options
decodeURIComponent 解码查询字符串的字符时使用的函数。默认为 querystring.unescape()。
maxKeys 指定要解析的键的最大数量。指定为 0 则不限制。默认为 1000。
-
HTTP 模块概要
http.createServer([options][, requestListener])
2. node中的异步和同步
fs模块对文件的几乎所有操作都有同步和异步两种形式
例如:readFile() 和 readFileSync()
区别:
同步调用会阻塞代码的执行,异步则不会
异步调用会将读取任务下达到任务队列,直到任务执行完成才会回调
异常处理方面,同步必须使用 try catch 方式,异步可以通过回调函数的第一个参数
var fs=require('fs')
console.time('sync');
try {
var data = fs.readFileSync('./c.txt');
console.log(data);
} catch (error) {
throw error;
}
console.timeEnd('sync');
console.time('async');
fs.readFile('./c.txt',(error, data) => {
if (error) throw error;
console.log(data);
});
console.timeEnd('async');
3.自己写一个node服务器
- 普通静态资源服务器
var http=require('http');
//文件模块 操作文件 读取文件,写入文件
var fs=require('fs');
function read(str,res){
fs.readFile(str,function(err,data){
if(!err){
res.write(data);
res.end();
}
})
}
var server=http.createServer(function(req,res){ // /img/2.gif
//接受请求, 做出应有
console.log(req.url);//请求路径 端口后面的,参数前面的 / /favicon.ico
if(req.url=='/'){
read('./index.html',res);
}else if(req.url=='/favicon.ico'){
read('./img/ico.png',res);
}else{
read('.'+req.url,res); // read('.'+'/img/2.gif',res)
}
});
//三个参数, 参数一:端口号(取值范围:0-65535,0-1024系统保留端口,80端口可以省略)
//参数二:域名(ip)
//参数三:回调函数
server.listen(3001,'127.0.0.1',function(err){
//err 错误对象参数 err-->null err--->{error:xxx}
if(!err){//正确
console.log('服务器成功运行在127.0.0.1:3000上')
}
})
- 带登录接口的服务器
-
index.html文件
<!-- action提交地址 --> <!-- get方式请求特点:1,把参数追加在url后面 2. 明文可见(不安全)3.大小大约为4k--> <form action="/api/login" method="get"> 用户名:<input type="text" name="user"> 密码:<input type="text" name="pass"> <button type="submit">登录</button> </form>
-
home.html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1>我是首页</h1> </body> </html>
-
server.js文件
var http=require('http'); var fs=require('fs'); // 处理url var url=require('url'); var json=[{user:'tom',pass:'123456'},{user:'kity',pass:'123'}]; function read(str,res){ fs.readFile(str,function(err,data){ if(!err){ res.write(data); res.end(); } }) } var server=http.createServer(function(req,res){ // url.parse(参数一:要解析的地址,是否把参数字符串解析成对象) var obj=url.parse(req.url,true) var pathname=obj.pathname;// 请求路径 var query=obj.query; // 请求参数 字符 ,对象 //console.log(req.url); /api/login?user=tom&pass=12345 if(pathname=='/'||pathname=='/index.html'){ read('./index.html',res); }else if(pathname=='/api/login'){ // 登录 for(var i=0;i<json.length;i++){ if(json[i].user==query.user&&json[i].pass==query.pass){ read('./index2.html',res); return; } } res.setHeader('Content-Type','text/plain;charset=utf-8'); res.write('登录失败'); res.end(); } }) server.listen(3000,function(err){ if(!err)console.log('服务器成功运行在3000端口上'); })