基於V8引擎(谷歌瀏覽器的引擎)渲染JS的工具或者環境javascript
npm(node Package Managernode模塊管理器)
:一個js模塊(全部封裝好可供其餘人調取使用的稱之爲模塊或者包)管理的工具,基於npm能夠安裝下載js模塊node xxx.js
Read-Evaluate-Print-Loop
輸入-求值-輸出-循環多數人把node稱之爲後臺編程語言,是由於:css
傳統後臺語言:JAVA/Python/PHP/C#html
- JS運行在客戶端瀏覽器中=>前端
- 瀏覽器給js提供不少全局的屬性和方法
window.setTimeout...
- JS運行在服務器端的node中=>後臺
- NODE也給js提供不少內置的屬性和方法:
http/fs/url/path...
等對象中都提供不少API供js操做
- 前端(瀏覽器運行js)是限制I/O操做的
input type='file'
這種算是I/O操做,可是須要用戶手動選擇(並且僅僅是讀取不是寫入)- 後端(node中運行js) 不限制I/O操做
node自己是基於commonJS模塊規範設計的,因此模塊式node的組成前端
參考: CommonJS
:模塊設計思想(AMD/CMD/ES6 MOUDLE 都是模塊化設計思想)java
CommonJS給每個模塊(每個js)中都設置了內置的變量/屬性/方法node
module
: 表明當前這個模塊對象[object]module.exports
: 模塊的這個屬性是用來導出屬性方法的[object]exports
: 是內置的一個變量,也是用來導出當前模塊屬性方法的,雖然和module.exports
不是一個東西,可是對應的值是一個(module.exports=exports
值都是對象)require
: CommonJS提供的內置變量,用來導入模塊的(其實導入的是moudle.exports
暴露出來的東西)
about_node.js
模塊中的代碼自上而下執行,把exports對應對內存導入進來,因此接受的結果是一個對象require
是一個同步操做:只有把導入的模塊代碼執行完成,才能夠獲取值,而後繼續執行本模塊下面的代碼let temp1 = require('./about_node');
//=> ./
是特地指定當前目錄中的某個模塊(.js
能夠省略)require('./xxx')
或者../xxx
或者 /xxx
這種本身制定的路徑的模式,都是爲了導入自定義的模塊,換句話說,想要導入自定義的模塊,必須加路徑jquery
require('./xxx')
首先到當前項目中的node_modules
中查找是否存在這個模塊,不存在找node提供的內置模塊(導入第三方或者內置的)web
__dirname
: 模塊中這個內置變量是當前模塊所在的絕對路徑(具體到盤符:物理路徑)
console.log(__dirname)
C:\Users\lenovo\Desktop\notes\NODE
__filename
: 相對於_dirname來說,多了模塊名稱 (即對了文件名稱)
C:\Users\lenovo\Desktop\notes\NODE\about_node.js
// about_node.js
let a = 12;
let fn = b => {
return a * b
}
// console.log(1)
// setTimeout(()=>{
// console.log(1.5)
// },1000)
exports.fn = fn; // 把當前模塊私有的函數放到exports導出對象中(賦值給他的某一個屬性),這樣在其餘模塊中,能夠基於require導入進來使用 <=> moudle.exports.fn = fn
// console.log(2)
console.log(__dirname); //C:\Users\lenovo\Desktop\notes\NODE
console.log(__filename) //C:\Users\lenovo\Desktop\notes\NODE\about_node.js
複製代碼
// about_node2.js
let a = 2;
let fn = b => {
return a / b
}
let temp1 = require('./about_node'); // ./ 是特地指定當前目錄中的某個模塊(.js能夠省略)
// console.log(3); // 1 2 3 先把about_node.js中的代碼所有執行完,再執行about_node2.js中的代碼
// // 若是加定時器 1 2 3 1.5
// console.log(temp1); //此時temp1是個對象 {fn:...}
console.log(temp1.fn(10)); //120 用的是about_node.js中的變量a和fn
// // 第二次並無把about_node.js執行,由於第一次執行把導出的結果緩存了 但不多寫兩次
// temp1 = require('./about_node');
// console.log(temp1.fn(10)); //120
複製代碼
【內置模塊fs:實現I/O操做】ajax
經常使用方法:sql
fs.mkdir / fs.mkdirSync
:建立文件夾 有Sync的是同步建立,反之是異步,想要實現無阻塞I/O操做,咱們通常用異步完成 fs.mkdir(path,callback)
f
s.mkdirSync(path)`fs.readsir / fs.readdirSync
:讀取文件目錄中的內容fs.rmdir / fs.rmdirSync
:刪除文件夾(若是文件夾中有內容不能刪除)fs.readFile
:讀取文件中內容fs.writeFile
:向文件中寫入內容(覆蓋寫入:寫入的新內容會替換原有內容)fs.appendFile
:追加寫入新內容,原有內容還在fs.copyFile
:拷貝文件到新的位置fs.unlink
:刪除文件let fs = require('fs');
//建立文件夾 同步會形成阻塞,通常用異步
fs.mkdir('./less',(err)=>{
if(err){
console.log(err);
return;
}
console.log('ok');
});
console.log(1);
//讀取文件目錄 異步
fs.readdir('./',(err,result)=>{
if(err){、
// console.log(err);
return;
};
console.log(result); // 當前文件目錄 ['less', 'module_fs.js'] 返回結果是一個數組
});
//刪除文件夾 (必須保證文件夾是空的)
fs.rmdir('./less',err=>{
if(err){
console.log(err);
return;
}
console.log('ok');
})
/* 若是文件夾中有內容 則會報錯{ [Error: ENOTEMPTY: directory not empty, rmdir 'C:\Users\lenovo\Desktop\notes\NODE\module_fs\less'] */
// 讀取文件內容
fs.readFile('./less/less.js','utf-8',(err,result)=>{
if(err){
// console.log(err);
return;
}
console.log(result);//文件內容(字符串格式) setTimeout(()=>{console.log(123) },1000)
// 不設置utf-8編碼格式,讀取出來的是buffer格式的數據,設置事後是字符串格式數據
})
// 向文件中寫入內容(覆蓋寫入)
fs.writeFile('./less/less.js','哈哈','utf-8',(err)=>{
//第二個參數是文件寫入的內容 會覆蓋原內容
})
// 向文件中寫入內容(追加寫入)
fs.appendFile('./less/less.js','嘿嘿','utf-8',(err)=>{
//第二個參數是文件寫入的內容 追加在原內容後
})
// 刪除文件
fs.unlink('./less/less.js',(err)=>{
if(err){
return;
}
console.log('ok')
})
複製代碼
【url內置模塊】
url.parse(url[,flag]):
Url {
- protocol: 'http:', //=>協議
- slashes: true, //=>是否有雙斜線
- auth: null, //=>
- host: 'baidu.com', //=>域名+端口
- port: null, //=>端口
- hostname: 'baidu.com', //=>域名
- hash: '#video', //=>哈希值
- search: '?from=qq&lx=stu', //=> 問號傳參[string]
- query: 'from=qq&lx=stu', //=>問號傳參[string] 不包含問號
- pathname: '/', //=> 請求資源的路徑名稱
- path: '/?from=qq&lx=stu', //=>pathname + search
- href: 'baidu.com/?from=qq&am…' //=> url地址 }
let url = require('url');
console.log(url.parse('http://baidu.com?from=qq&lx=stu#video',true));
// 返回一個url對象
複製代碼
【http內置模塊】
服務器端任務
注意:基於node建立後臺程序,咱們通常都建立一個server模塊,在模塊中實現建立web服務,和對於請求的處理(通常會把server模塊放到當前項目的根目錄下)
//導入內置模塊
let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
//建立web服務
let port = 80;
let server = http.createServer((req,res)=>{
/* 當服務建立成功,而且客戶端向當前服務發送了請求才會執行回調函數,而且發送一次請求,回調函數就會觸發執行一次 客戶端如何向建立的服務器發送請求? 對應好協議、域名、端口等信息,在瀏覽器中或者ajax等中發送請求便可 http://localhost:80/... 服務在電腦上,localhost本機域名,也就是本機的客戶端服務器,訪問本機的服務器端程序(也就是本身的電腦既是客戶端又是服務器端) http://內網ip:80/... IP作域名訪問,若是是內網IP,相同局域網下的用戶能夠訪問這個服務,若是是外網IP,全部能聯網的基本上均可以訪問這個服務(局域網下訪問,須要互相關掉防火牆) 查看內網IP:在CMD中輸入ipconfig => 172.18.0.80 localhost:80/ 等同於 172.18.0.80:80/ */
console.log('hello world!');
});
server.listen(port,()=>{
//回調函數:當服務建立成功,而且端口號也已經監聽成功後,觸發的回調函數
console.log(`server is success,listen${port}!`); // server is success,listen80!
});//監聽一個端口 [0~65535]
//http.createServer().linten(80);
// 當服務建立成功,命令行中會一直存在光標閃爍,證實服務器正在運行中(必定要保證服務試運行的),ctrl+c => 結束運行服務
複製代碼
兩個參數
req:require
請求對象,包含了客戶端的請求信息(不包括hash值)req.url
存儲的是請求資源的路徑地址以及問號傳參req.method
客戶端請求方式req.headers
客戶端的請求頭信息(是一個對象)res:response
響應對象,包含了一些屬性和方法,可讓服務器端返回給客戶端內容res.write
基於這個方法,服務器端能夠向客戶端返回內容res.end
結束響應 -res.writeHead
重寫響應頭信息 (是一個對象)res.writeHead(200,{
'content-Type':'text/plain;charset=utf-8'
// text/plain 純文本類型
})
複製代碼
res.setHeader
重寫響應頭信息 (不用寫狀態碼) res.setHeader('Content-type','text/html; charset=utf-8');
用url模塊中的parse url.parse(req.url)
// 把url中的路徑地址和問號傳參分別解析
let {pathname,query} = url.parse(req.url,true)
console.log(pathname,query);
/* /index.html [Object: null prototype] { uesr: 'tom', name: 'haha' } */
複製代碼
let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
//建立web服務
let port = 8080;
// let handle = function handle(req,res){
// }
// http.createServer(handle).listen(port);
let server = http.createServer((req,res)=>{
// console.log(url,method,headers);
// // 獲取請求頭中某個具體信息
// console.log(headers['user-agent']);
/* /?user=tom GET 請求頭:{ host: 'localhost:8080', connection: 'keep-alive', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,;q=0.8,application/signed-exchange;v=b3', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9' } */
// res.write('hello world!');
// res.end('hello world!'); //表示服務器端返回字符串內容並結束響應 通常返回的是string或者buffer格式的數據
//重寫響應頭信息 是一個對象 (中文設置)
/* 對象有兩個參數 1. HTTP狀態碼 2.'content-Type':'text/plain;charset=utf-8' 解決中文亂碼問題 */
res.writeHead(200,{
'content-Type':'text/plain;charset=utf-8'
// text/plain 純文本類型
})
res.end(JSON.stringify({name:'哈哈哈'}));//{"name":"xxx"} 返回JSON格式的字符串
});
server.listen(port);
複製代碼
npm -v
查看nom版本號npm install
安裝npm init -y
配置項目清單
package.json
文件// package.json文件
{
"name": "NODE",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"server": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
複製代碼
<input type="text" id="txt" />
複製代碼
txt.onblur = function () {
jsonp({
callback:'cb',
url:"http://localhost",
data:{
user:this.value
},
success:function(data){
console.log(data);
}
})
}
function jsonp(json) {
let opt = {
callback: 'callback',
url: '',
data: {},
}
let fnName = json.fname || 'jQuery_' + (Date.now());
window[fnName] = function (data) {
json.success(data);
// delete window[fnName];
window[fnName] = null;
}
//動態建立都異步
let oS = document.createElement('script');
// oS.src = json.url + '?' +new URLSearchParams(json.data) + '&'+json.callback+'='+fnName;
json.data[json.callback] = fnName; //cb=jquery_231231
oS.src = json.url + '?' + new URLSearchParams(json.data);
document.querySelector('head').appendChild(oS);
oS.remove();
}
複製代碼
// 服務器端
//建立服務器
const http = require('http');
//建立服務
let sql = [
{
user: 'Tom',
password: 123
},
{
user: 'Jess',
password: 1234
},
{
user: 'Alex',
password: 12345
}
];
const app = http.createServer((request, response) => {
let url = request.url; //接受客戶端發送的請求(參數:key=val&key2=val2... 此參數是字符串)
let obj = {};
if (url !== '/favicon.ico') {
// 把url字符串轉化爲對象 把字符串先轉成數組,再把數組轉成對象
url.split('?').split('&').forEach(item => {
let ary = item.split('=');
console.log(ary)
obj[ary[0]] = ary[1];
});
// 判斷數組中是否有發送來的用戶名
let isExist = sql.find(e => e.user === obj.user);
console.log(isExist)
// 中文設置
response.setHeader('Content-Type', 'text/html; charset=utf-8');
// 若是數據數組中有,說明用戶名被佔用
// obj.cb 是後臺返回給前臺的數據
if (isExist) {
response.write(obj.cb + "({code:1,msg:'用戶名已被註冊'})");
} else {
response.write(obj.cb + "({code:0,msg:'註冊成功'})");
}
response.end();
}
})
//端口監聽
app.listen(80)
複製代碼
fetch('/post',{
body:'user=xiaoqiang',
method:'post',
headers:{
'Content-Type':'application/x-www-form-urlencoded'
}
}).then(e=>e.json())
.then(d=>{
console.log(d);
});
複製代碼
// 服務器端
const http = require('http');
const fs = require('fs');
const querystring = require('querystring');
// const
let sql = ['zhiqiang']
http.createServer((req,res)=>{
let url = req.url;
if(url !== '/favicon.ico'){
//走文件
if(url.includes('.html')){
try {
let d = fs.readFileSync('./www'+url);
res.write(d.toString());
} catch (error) {
let er = fs.readFileSync('./www/404.html');
res.write(er.toString());
}
res.end();
}else{
//走接口
if(url === '/post'){
let str = '';
req.on('data',(d)=>{
// console.log(d.toString())
str += d;
});
req.on('end',()=>{
// console.log(str.toString(),111);
let obj = querystring.parse(str);
// console.log(.user)
res.setHeader('Content-Type','text/html;charset=utf-8');
if(sql.includes(obj.user)){
res.write(JSON.stringify({code:0,msg:"失敗"}));
}else{
res.write(JSON.stringify({code:1,msg:"成功"}));
}
res.end();
});
}
}
}
}).listen(80);
複製代碼
====
服務器上有一堆項目代碼,這堆項目代碼中既可能有服務器端的程序代碼,也可能有客戶端的程序代碼,而客戶端的程序代碼咱們通常放到static(靜態的)這個文件夾當中
static/publice
: 都是服務器端須要返回給客戶端,有客戶端瀏覽器渲染和解析的(前端項目:包括頁面、css、js、圖片等)
server.js
: 都是須要在服務器端基於node執行的(後端項目:通常只有js)