孤独易冷 發表於 2021-1-7 11:36:00

Node.js的基本使用

<h2>1、node的基本介绍</h2>
<p>常说的 node 和 nodejs 没有什么区别,它们就是同一个东西。</p>
<p>Node 是一个基于Chrome V8引擎的JavaScript运行环境,一个可以让 JavaScript 运行在服务端的开发平台。它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。</p>
<p>Node是一个基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。简单地说,Node.js 就是运行在服务端的 JavaScript。</p>
<p>所以 Node.js 可以说是一个运行平台,也可以说是一种语言。</p>
<p>&nbsp;</p>
<h3>1.1、什么是V8引擎</h3>
<div>
<div>
<p>JavaScript一种解释性脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分。</p>
<p>V8 引擎就是JavaScript运行的解释器,他是Google开发的,作为 chrome 浏览器的 js 执行解释器,因为性能十分优秀,速度非常快,所以后来慢慢的也就被广泛的使用,不仅仅局限在chrome中解释js了,下文的nodejs就是用到了v8引擎。</p>
</div>
</div>
<p>&nbsp;</p>
<h2>2、nodejs 的安装</h2>
<p>node.js 的安装可参考:http://www.runoob.com/nodejs/nodejs-install-setup.html。一般来说,nodejs 在安装后会自动配置好环境变量。历史版本下载:https://nodejs.org/dist/</p>
<p>&nbsp;</p>
<p>在安装完后,可以运行 node -v 或者 node --version 命令来查看 node 是否安装成功,有输出版本即证明已安装成功:</p>
<p><img src="https://img2020.cnblogs.com/blog/1424359/202101/1424359-20210107112715312-381624442.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<h3>2.1、在Windows 7上安装Node.js 16(或更高版本)的方法</h3>
<p>参考:https://www.quyu.net/info/1792.html</p>
<p>&nbsp;</p>
<h2>3、如何运行一个node程序</h2>
<p>运行一个 node 程序非常简单。在安装完 node 之后,我们可以编写一个 JS 文件,比如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">helloworld.js 文件</span>
console.log("Hello World");</pre>
</div>
<p>然后用 node 命令执行该文件:</p>
<div class="cnblogs_code">
<pre>node helloworld.js   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">将输出 Hello World</span></pre>
</div>
<p>&nbsp;</p>
<p>我们也可以打开终端,键入 node 后进入命令交互模式,可以输入一条代码语句后立即执行并显示结果,例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">$ node
</span>&gt; console.log('Hello World!'<span style="color: rgba(0, 0, 0, 1)">);
Hello World</span>!</pre>
</div>
<p>&nbsp;</p>
<h2>4、node.js创建一个 http 服务</h2>
<p>如果我们使用 PHP 来编写后端的代码时,需要 Apache 或者 Nginx 的HTTP服务器,并配上 mod_php5 模块和 php-cgi 。从这个角度看,整个"接收HTTP请求并提供Web页面"的需求根本不需要PHP来处理,而是由服务器来处理。</p>
<p>不过对Node.js来说,概念完全不一样了。<strong>使用Node.js时,我们不仅仅在实现一个应用,同时还实现了整个HTTP服务器</strong>。事实上,我们的Web应用以及对应的Web服务器基本上是一样的。</p>
<p>node.js 并不需要额外搭建一个服务器比如 Apache、tomcat 这些,在我们创建 node.js 应用时,它同时也搭建了一个 http 服务器。所以说我们不仅仅实现了一个应用,同时也实现了整个 http 服务器。</p>
<p>另外,node.js不仅仅可以创建http服务,也可以充当一个客户端,即向http服务器发出请求。</p>
<p>&nbsp;</p>
<h3>4.1、如何创建一个http服务</h3>
<p>首先我们新建一个 server.js 文件。</p>
<p>先使用&nbsp;<strong>require</strong>&nbsp;指令来载入 http 模块,并将实例化的 HTTP 赋值给变量 http。http 模块是 node.js 自带的模块,安装了 node 之后直接引用即可,无需再用 npm 下载。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> http = require("http");</pre>
</div>
<p>然后使用 http.createServer() 方法创建服务器,并使用 listen 方法绑定 8888 端口。createServer&nbsp;里面的回调函数将通过 request, response 参数来接收和响应数据。完整代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">server.js 文件:</span>

<span style="color: rgba(0, 0, 255, 1)">var</span> http = require('http'<span style="color: rgba(0, 0, 0, 1)">);
http.createServer(</span><span style="color: rgba(0, 0, 255, 1)">function</span> (request, response) {   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">createServer 函数会返回一个对象,通过该对象的 listen 的方法可以指定这个 HTTP 服务器监听的端口号</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 发送 HTTP 头部 </span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> HTTP 状态值: 200 : OK</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 内容类型: text/plain</span>
    response.writeHead(200, {'Content-Type': 'text/plain'<span style="color: rgba(0, 0, 0, 1)">});

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 发送响应数据 "Hello World"</span>
    response.write("Hello world!"<span style="color: rgba(0, 0, 0, 1)">);
    response.end();    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">也可以直接 response.end("hello world"),此时相当于先调用了 response.write(data) 之后再调用 response.end()</span>
}).listen(8888);</pre>
</div>
<p>由此一个 http 服务已经搭建完成。</p>
<p>使用 node 命令执行 server.js 文件代码:</p>
<div class="cnblogs_code">
<pre>node server.js</pre>
</div>
<p>接下来,通过页面访问该服务或者直接通过浏览器访问 http://localhost:8888/,就可以看到该服务的响应结果:</p>
<p><img src="https://img2020.cnblogs.com/blog/1424359/202101/1424359-20210107150040725-1680004236.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<h2>5、node.js 的模块系统</h2>
<p>为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。</p>
<p>&nbsp;</p>
<h3>5.1、导入模块的用法(require)</h3>
<p>require() 函数用于在当前模块中加载别的模块。在函数内写入模块的路径即可(相对路径和绝对路径都行)。<strong>node.js 默认后缀为 js,所以可忽略 .js 扩展名</strong></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> foo1 = require('./foo'); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> .js 扩展名可忽略</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> foo2 = require('./foo.js'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> data = require('./data.json'); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">不仅仅是 JS 文件,也可以是其他文件</span></pre>
</div>
<p>require 相当于module.exports的传送门,module.exports后面的内容是什么,require的结果就是什么,比如对象、数字、字符串、函数等,然后再把require的结果赋值给某个变量。</p>
<p>&nbsp;</p>
<p>require理论上可以运用在代码的任何地方,甚至不需要赋值给某个变量之后再使用,比如:</p>
<div class="cnblogs_code">
<pre>require('./a')(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">假设a模块是一个函数,此时将立即执行a模块函数</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> data = require('./a').data; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">假设a模块导出的是一个对象</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> a = require('./a'); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">假设a模块导出的是一个数组</span></pre>
</div>
<p>&nbsp;</p>
<h3>5.2、导出模块的用法(exports)</h3>
<p>exports 对象是当前模块的导出对象,用于导出该模块的方法或属性。</p>
<p>别的模块通过 require() 函数引用别的模块时实际上得到的就是别的模块的 exports 对象:</p>
<div class="cnblogs_code">
<pre>exports.hello = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
    console.log(</span>'Hello World!'<span style="color: rgba(0, 0, 0, 1)">);
};</span></pre>
</div>
<p>&nbsp;</p>
<p>导出模块的方法或者属性可以直接用 exports,也可以使用 module.exports 来进行导出。通过<code>module</code>对象可以访问到当前模块的一些相关信息,但最多的用途是替换当前模块的导出对象。</p>
<div class="cnblogs_code">
<pre>module.exports = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
    console.log(</span>'Hello World!'<span style="color: rgba(0, 0, 0, 1)">);
};</span></pre>
</div>
<p>实际上,exports是module.exports的一个引用,module.exports 指向的就是&nbsp;exports。</p>
<div class="cnblogs_code">
<pre>console.log(exports === module.exports); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">输出true</span></pre>
</div>
<p>&nbsp;</p>
<p>如果要对外暴露属性或方法,就用&nbsp;exports&nbsp;就行,要暴露对象(类似class,包含了很多属性和方法),就用&nbsp;module.exports。</p>
<p>代码示例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">hello.js </span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Hello() {
    </span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> name;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.setName = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(thyName) {
      name </span>=<span style="color: rgba(0, 0, 0, 1)"> thyName;
    };
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sayHello = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">() {
      console.log(</span>'Hello ' +<span style="color: rgba(0, 0, 0, 1)"> name);
    };
};
module.exports </span>=<span style="color: rgba(0, 0, 0, 1)"> Hello;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">在 main.js 中引入 hello.js </span>
<span style="color: rgba(0, 0, 255, 1)">var</span> Hello = require('./hello'<span style="color: rgba(0, 0, 0, 1)">);
hello </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Hello();
hello.setName(</span>'BYVoid'<span style="color: rgba(0, 0, 0, 1)">);
hello.sayHello(); </span></pre>
</div>
<p>&nbsp;</p>
<h3>5.3、require 查找模块的策略</h3>
<p>由于 Node.js 中存在 4 类模块(原生模块和3种文件模块),尽管 require 方法极其简单,但是内部的加载却是十分复杂的,其加载优先级也各自不同。如下图所示:</p>
<p>原生模块指的就是 node.js 自带的模块,文件模块指的是项目本地的文件:</p>
<p><img src="https://img2020.cnblogs.com/blog/1424359/202101/1424359-20210107164555723-1030909608.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;加载顺序:</p>
<ol>
<li>
<p><strong>缓存。</strong>模块在第一次加载后会被缓存。 这也意味着(类似其他缓存机制)如果每次调用 require(‘foo’) 都解析到同一文件,则返回相同的对象。</p>
</li>
<li>
<p><strong>核心模块。</strong>核心模块定义在 Node.js 源代码的 lib/ 目录下。require() 总是会优先加载核心模块。 例如, require(‘http’) 始终返回内置的 HTTP 模块,即使有同名文件。</p>
</li>
<li>
<p><strong>文件模块。</strong>如果按确切的文件名没有找到模块,则 Node.js 会尝试带上 .js、 .json 或 .node 拓展名再加载。<code>当没有以 '/'、 './' 或 '../' 开头来表示文件时,这个模块必须是一个核心模块或加载自 node_modules 目录。</code></p>
</li>
<li>
<p><strong>目录作为模块。</strong>可以把程序和库放到一个单独的目录,然后提供一个单一的入口来指向它。</p>
</li>
<li>
<p><strong>&nbsp;node_modules 目录加载</strong></p>
</li>
<li>
<p><strong>&nbsp;从全局目录加载。</strong>NODE_PATH检索,如果 NODE_PATH 环境变量被设为一个以冒号分割的绝对路径列表,则当在其他地方找不到模块时 Node.js 会搜索这些路径。其他全局目录,$HOME/.node_modules (其中 $HOME 是用户的主目录)等等</p>
</li>
</ol>
<p>粗略记录一下,详细可自行查阅资料。</p>
<p>&nbsp;</p>
<h2>6、node.js 路由</h2>
<p>通过路由,我们可以根据不同的 URL 来执行不同的代码,进行不同的处理。</p>
<p>&nbsp;</p>
<h3>6.1、解析URL参数(url、querystring模块)</h3>
<p>URL 等一系列的参数和数据都存在 request 对象中,为了解析这些数据,我们需要额外的 Node.JS 模块,它们分别是 url 和 querystring 模块。这两个模块都是 node.js 自带的,所以不用额外安装。<br>比如访问一个路径:http://localhost:8080/start?foo=bar&amp;hello=world</p>
<p>url.parse(reqObj.url) 解析出来的是一个对象,格式如下:</p>
<div class="cnblogs_code">
<pre><span>Url {
protocol: null<span>,
slashes: null<span>,
auth: null<span>,
host: null<span>,
port: null<span>,
hostname: null<span>,
hash: null<span>,
search: '?foo=bar&amp;hello=world'<span>,
query: 'foo=bar&amp;hello=world'<span>,
pathname: '/start'<span>,
path: '/start?foo=bar&amp;hello=world'<span>,
href: '/start?foo=bar&amp;hello=world'<span>
}</span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
</div>
<p>querystring.parse(str) 方法将字符串转换为对象。</p>
<p class="prettyprint prettyprinted"><span class="pln">  1、url<span class="pun">.<span class="pln">parse<span class="pun">(<span class="kwd">reqObj.url<span class="pun">).<span class="pln">query&nbsp; 该方法返回 URL 的参数,即 foo=bar&amp;hello=world</span></span></span></span></span></span></span></p>
<p class="prettyprint prettyprinted"><span class="pln"><span class="pln">  2、url<span class="pun">.<span class="pln">parse<span class="pun">(<span class="kwd">reqObj.url<span class="pun">).pathname</span></span></span></span></span></span></span><span class="pln"><span class="pun"><span class="pln"><span class="pun"><span class="kwd"><span class="pun"><span class="pln">&nbsp; 该方法返回虚拟目录,即 /start</span></span></span></span></span></span></span></p>
<p class="prettyprint prettyprinted">&nbsp;</p>
<div>  3、querystring.parse(queryStr)["foo"]&nbsp; 该方法返回 URL 参数中某个属性值,即上述 URL 中的 bar</div>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> http = require("http"<span style="color: rgba(0, 0, 0, 1)">),
    url </span>= require("url"<span style="color: rgba(0, 0, 0, 1)">);
    querystring </span>= require('querystring'<span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> onRequest(request, response) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取请求路径</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span> pathname =<span style="color: rgba(0, 0, 0, 1)"> url.parse(request.url).pathname;
    </span><span style="color: rgba(0, 0, 255, 1)">var</span> queryStr =<span style="color: rgba(0, 0, 0, 1)"> url.parse(request.url).query;

    </span><span style="color: rgba(0, 0, 255, 1)">var</span> fooVal = querystring.parse(queryStr)["foo"<span style="color: rgba(0, 0, 0, 1)">];
    </span><span style="color: rgba(0, 0, 255, 1)">var</span> helloVal = querystring.parse(queryStr)["hello"<span style="color: rgba(0, 0, 0, 1)">];

    console.log(</span>'解析出的数据:', pathname, query, fooVal, helloVal);   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">将输出:解析出的数据: /start foo=bar&amp;hello=world bar world</span>
}</pre>
</div>
<p>&nbsp;</p>
<h3>6.2、通过路由对不同URL进行不同响应</h3>
<p>通过路由,我们可以根据不同的 URL 来执行不同的代码,进行不同的处理。</p>
<p>首先我们创建一个 server 模块。跟之前不同的是,这里扩展了服务器的 start() 函数,以便将路由函数作为参数传递过去:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> server.js文件</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> http = require("http"<span style="color: rgba(0, 0, 0, 1)">),
    url </span>= require("url"<span style="color: rgba(0, 0, 0, 1)">);
    querystring </span>= require('querystring'<span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> start(route, handle) {

    </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> onRequest(request, response) {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取请求路径</span>
      <span style="color: rgba(0, 0, 255, 1)">var</span> pathname =<span style="color: rgba(0, 0, 0, 1)"> url.parse(request.url).pathname;

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 关闭nodejs 默认访问 favicon.ico</span>
      <span style="color: rgba(0, 0, 255, 1)">if</span> (!pathname.indexOf('/favicon.ico'<span style="color: rgba(0, 0, 0, 1)">)) {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
      };

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 收到来自 pathname 的请求</span>
      console.log("收到来自 " + pathname + " 的请求"<span style="color: rgba(0, 0, 0, 1)">);

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 路由器处理</span>
<span style="color: rgba(0, 0, 0, 1)">      route(handle, pathname);

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回数据</span>
      response.writeHead(200, {"Content-type": "text/plain"<span style="color: rgba(0, 0, 0, 1)">});
      response.write(</span>"Hello world!"<span style="color: rgba(0, 0, 0, 1)">);
      response.end();
    }

    http.createServer(onRequest).listen(</span>8080<span style="color: rgba(0, 0, 0, 1)">);
    console.log(</span>"Server has start!"<span style="color: rgba(0, 0, 0, 1)">);
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开放接口</span>
exports.start = start;</pre>
</div>
<p>然后创建一个路由模块:router.js 文件:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 路由模块,针对不同的请求,做出不同的响应。 handle:处理请求方法</span>

<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> route(handle, pathname) {
    console.log(</span>"路由处理来自 " + pathname + "的请求"<span style="color: rgba(0, 0, 0, 1)">);

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 检查给定的路径对应的请求处理程序是否存在,如果存在的话直接调用相应的函数</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">typeof</span> handle == "function"<span style="color: rgba(0, 0, 0, 1)">) {
      handle();
    } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
      console.log(</span>"路由没有对应的处理函数:" +<span style="color: rgba(0, 0, 0, 1)"> pathname);
    }
}

exports.route </span>= route;</pre>
</div>
<p>创建一个处理不同请求的程序模块:requestHandlers.js:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 存放不同的处理程序,和请求的URL相对应</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> start() {
    console.log(</span>"start 路由处理函数"<span style="color: rgba(0, 0, 0, 1)">);
}

</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> upload() {
    console.log(</span>"upload 路由处理函数"<span style="color: rgba(0, 0, 0, 1)">);
}

exports.start </span>=<span style="color: rgba(0, 0, 0, 1)"> start;
exports.upload </span>= upload;</pre>
</div>
<p>创建一个 index.js 文件,使得路由函数可以被注入到服务器中:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> server = require("./server"<span style="color: rgba(0, 0, 0, 1)">),
    router </span>= require("./router"<span style="color: rgba(0, 0, 0, 1)">),
    requestHandlers </span>= require("./requestHandlers"<span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> handle 保存不同请求路径对应的处理方法</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> handle =<span style="color: rgba(0, 0, 0, 1)"> {};

handle[</span>"/"] =<span style="color: rgba(0, 0, 0, 1)"> requestHandlers.start;
handle[</span>"/start"] =<span style="color: rgba(0, 0, 0, 1)"> requestHandlers.start;
handle[</span>"/upload"] =<span style="color: rgba(0, 0, 0, 1)"> requestHandlers.upload;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 传入路由模块方法, 路径处理方法</span>
server.start(router.route, handle);</pre>
</div>
<p>将服务器跑起来即可:</p>
<div class="cnblogs_code">
<pre>node index.js</pre>
</div>
<p>此时我们如果访问&nbsp;http://localhost:8080/start?foo=bar&amp;hello=world,服务器将会执行 start() 函数,控制台输出:start 路由处理函数。由此便实现了通过路由针对不同 URL 进行不同处理。</p>
<p><strong>其实路由就是封装一个函数 route,然后在&nbsp;http模块 的&nbsp;createServer 函数里面的回调函数执行该函数并将路径作为参数传递,在路由函数 route 中将会根据不同的路径测试进行不同处理。</strong></p>
<p>&nbsp;</p>
<h2>7、全局对象(global)</h2>
<p>在 JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。在浏览器的 JavaScript 中,通常 window 是全局对象。</p>
<p>而在 Node.js 中,全局对象是 global,所有的全局变量(除了 global 本身以外)实际上都是 global 对象的属性。在 Node.js 我们可以直接使用变量名,而不必要带上global前缀。</p>
<p>global 最根本的作用是作为全局变量的宿主。如果我们要自己定义 global 属性,需要在定义的时候加上 global 前缀,比如 global.age = 11。当你定义一个全局变量时,这个变量同时也会成为全局对象的属性。</p>
<p>&nbsp;</p>
<p>通过输出 global 可以查看全局变量:</p>
<div class="cnblogs_code">
<pre>console.log(global);   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">通过console.log只会输出enumerable属性</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)">输出如下:</span>
&lt;ref *1&gt;<span style="color: rgba(0, 0, 0, 1)"> Object {
global: ,
clearInterval: ,
clearTimeout: ,
setInterval: ,
setTimeout: {
    :
},
queueMicrotask: ,
clearImmediate: ,
setImmediate: {
    :
}
}

console.log(Object.getOwnPropertyNames(global));   </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">我们可以通过console.log(Object.getOwnPropertyNames(global))看到全部属性</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)">输出如下:</span>
<span style="color: rgba(0, 0, 0, 1)">[
</span>'Object',             'Function',             'Array'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Number',             'parseFloat',         'parseInt'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Infinity',         'NaN',                  'undefined'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Boolean',            'String',               'Symbol'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Date',               'Promise',            'RegExp'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Error',            'EvalError',            'RangeError'<span style="color: rgba(0, 0, 0, 1)">,
</span>'ReferenceError',   'SyntaxError',          'TypeError'<span style="color: rgba(0, 0, 0, 1)">,
</span>'URIError',         'globalThis',         'JSON'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Math',               'console',            'Intl'<span style="color: rgba(0, 0, 0, 1)">,
</span>'ArrayBuffer',      'Uint8Array',         'Int8Array'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Uint16Array',      'Int16Array',         'Uint32Array'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Int32Array',         'Float32Array',         'Float64Array'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Uint8ClampedArray','BigUint64Array',       'BigInt64Array'<span style="color: rgba(0, 0, 0, 1)">,
</span>'DataView',         'Map',                  'BigInt'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Set',                'WeakMap',            'WeakSet'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Proxy',            'Reflect',            'decodeURI'<span style="color: rgba(0, 0, 0, 1)">,
</span>'decodeURIComponent', 'encodeURI',            'encodeURIComponent'<span style="color: rgba(0, 0, 0, 1)">,
</span>'escape',             'unescape',             'eval'<span style="color: rgba(0, 0, 0, 1)">,
</span>'isFinite',         'isNaN',                'SharedArrayBuffer'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Atomics',            'FinalizationRegistry', 'WeakRef'<span style="color: rgba(0, 0, 0, 1)">,
</span>'WebAssembly',      'global',               'process'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Buffer',             'URL',                  'URLSearchParams'<span style="color: rgba(0, 0, 0, 1)">,
</span>'TextEncoder',      'TextDecoder',          'clearInterval'<span style="color: rgba(0, 0, 0, 1)">,
</span>'clearTimeout',       'setInterval',          'setTimeout'<span style="color: rgba(0, 0, 0, 1)">,
</span>'queueMicrotask',   'clearImmediate',       'setImmediate'<span style="color: rgba(0, 0, 0, 1)">
]</span></pre>
</div>
<p>可以看到,在全局对象里有一个 global 属性指向全局对象自己,也正是因为在全局对象里放了一个 global 属性指向了全局对象自己,所以才可以使用 global 访问全局对象。所以说,global, global.global, global.global.global ... 实际上都是同一个对象。</p>
<p>&nbsp;</p>
<h3>7.1、全局函数(console)</h3>
<p>console 用于提供控制台标准输出,它是由 Internet Explorer 的 JScript 引擎提供的调试工具,后来逐渐成为浏览器的实施标准。Node.js 沿用了这个标准,提供与习惯行为一致的 console 对象,用于向标准输出流(stdout)或标准错误流(stderr)输出字符。</p>
<p>以下为 console 对象的一系列方法:</p>
<p>其中 console.log() 非常常用,该方法用于向标准输出流打印字符并以换行符结束。console.log 接收若干个参数,如果只有一个参数,则输出这个参数的字符串形式。如果有多个参数,则 以类似于C 语言 printf() 命令的格式输出。</p>
<p><img src="https://img2020.cnblogs.com/blog/1424359/202101/1424359-20210108141700346-1919348585.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<h3>7.2、全局变量 process</h3>
<p>process 对象是 Node 的一个全局对象,即 global 对象的属性,它提供当前 Node 进程的信息,用于描述当前Node.js 进程状态。该对象部署了<code>EventEmitter</code>接口。</p>
<p><code class="language-plaintext highlighter-rouge">process</code>对象提供一系列属性,用于返回系统信息:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">process.argv</code>:返回一个数组,成员是当前进程的所有命令行参数。</li>
<li><code class="language-plaintext highlighter-rouge">process.env</code>:返回一个对象,成员为当前Shell的环境变量,比如<code class="language-plaintext highlighter-rouge">process.env.HOME</code>。</li>
<li><code class="language-plaintext highlighter-rouge">process.installPrefix</code>:返回一个字符串,表示 Node 安装路径的前缀,比如<code class="language-plaintext highlighter-rouge">/usr/local</code>。相应地,Node 的执行文件目录为<code class="language-plaintext highlighter-rouge">/usr/local/bin/node</code>。</li>
<li><code class="language-plaintext highlighter-rouge">process.pid</code>:返回一个数字,表示当前进程的进程号。</li>
<li><code class="language-plaintext highlighter-rouge">process.platform</code>:返回一个字符串,表示当前的操作系统,比如<code class="language-plaintext highlighter-rouge">Linux</code>。</li>
<li><code class="language-plaintext highlighter-rouge">process.title</code>:返回一个字符串,默认值为<code class="language-plaintext highlighter-rouge">node</code>,可以自定义该值。</li>
<li><code class="language-plaintext highlighter-rouge">process.version</code>:返回一个字符串,表示当前使用的 Node 版本,比如<code class="language-plaintext highlighter-rouge">v7.10.0</code>。</li>
</ul>
<p><code class="language-plaintext highlighter-rouge">process</code>对象提供以下方法:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">process.chdir()</code>:切换工作目录到指定目录。</li>
<li><code class="language-plaintext highlighter-rouge">process.cwd()</code>:返回运行当前脚本的工作目录的路径。</li>
<li><code class="language-plaintext highlighter-rouge">process.exit()</code>:退出当前进程。</li>
<li><code class="language-plaintext highlighter-rouge">process.getgid()</code>:返回当前进程的组ID(数值)。</li>
<li><code class="language-plaintext highlighter-rouge">process.getuid()</code>:返回当前进程的用户ID(数值)。</li>
<li><code class="language-plaintext highlighter-rouge">process.nextTick()</code>:指定回调函数在当前执行栈的尾部、下一次Event Loop之前执行。</li>
<li><code class="language-plaintext highlighter-rouge">process.on()</code>:监听事件。</li>
<li><code class="language-plaintext highlighter-rouge">process.setgid()</code>:指定当前进程的组,可以使用数字ID,也可以使用字符串ID。</li>
<li><code class="language-plaintext highlighter-rouge">process.setuid()</code>:指定当前进程的用户,可以使用数字ID,也可以使用字符串ID。</li>
</ul>
<p>参考:https://javascript.ruanyifeng.com/nodejs/process.html#toc0</p>
<p>&nbsp;</p>
<h4>7.2.1、process的属性env(process.env)</h4>
<p><code class="language-plaintext highlighter-rouge">process.env</code>属性返回一个对象,包含了当前Shell的所有环境变量。比如,<code class="language-plaintext highlighter-rouge">process.env.HOME</code>返回用户的主目录。</p>
<p>通常的做法是,新建一个环境变量<code class="language-plaintext highlighter-rouge">NODE_ENV</code>,用它确定当前所处的开发阶段,生产阶段设为<code class="language-plaintext highlighter-rouge">production</code>,开发阶段设为<code class="language-plaintext highlighter-rouge">develop</code>或<code class="language-plaintext highlighter-rouge">staging</code>,然后在脚本中读取<code class="language-plaintext highlighter-rouge">process.env.NODE_ENV</code>即可。</p>
<p>运行脚本时,改变环境变量,可以采用下面的写法:</p>
<div class="cnblogs_code">
<pre>$ export NODE_ENV=production &amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> node app.js
# 或者
$ NODE_ENV</span>=production node app.js</pre>
</div>
<p>&nbsp;</p>
<h3>7.3、node.js中的__filename和__dirname(绝对路径)</h3>
<p><strong>__filename</strong>&nbsp;表示文件所在位置的绝对路径,包括文件名。</p>
<p><strong>__dirname</strong>&nbsp;表示文件所在位置的绝对路径,但不包括文件名。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> index.js执行 node index.js</span>
console.log(__filename);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">输出F:\visualStudioCode\globalTest\index.js</span>
console.log(__dirname);   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">输出F:\visualStudioCode\globalTest</span></pre>
</div>
<p>_filename和_dirname都不是全局的,而是模块作用域下的。这两个属性不是全局对象下的属性,而是模块下的。如果你直接输出 global.__filename 会得到 undefined。</p>
<p>&nbsp;</p>
<h2>8、GET和POST请求</h2>
<h3>8.1、获取 GET 请求的参数</h3>
<p>GET 请求直接被嵌入在路径中,URL是完整的请求路径,包括了?后面的部分。获取 get 请求的参数可以用 node.js 内置的 url 和querystring 模块。详情可查看上面的 6.1解析URL参数(url、querystring模块)。</p>
<p>&nbsp;</p>
<h3>8.2、获取 POST 请求体的内容</h3>
<p>POST 请求的内容全部的都在请求体中,request 并没有一个属性内容为请求体,原因是等待请求体传输可能是一件耗时的工作,比如上传文件。而很多时候我们可能并不需要理会请求体的内容,恶意的POST请求会大大消耗服务器的资源,所以 node.js 默认是不会解析请求体的。</p>
<p>我们可以用以下方法来获取 post 请求体的内容:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> http = require('http'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> querystring = require('querystring'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> util = require('util'<span style="color: rgba(0, 0, 0, 1)">);

http.createServer(</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(req, res){
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义了一个post变量,用于暂存请求体的信息</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span> post = ''<span style="color: rgba(0, 0, 0, 1)">;   

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中</span>
    req.on('data', <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(chunk){   
      post </span>+=<span style="color: rgba(0, 0, 0, 1)"> chunk;
    });

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。</span>
    req.on('end', <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(){   
      post </span>= querystring.parse(post);   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里经过转换后将会是一个对象</span><span style="color: rgba(0, 0, 0, 1)">
      res.end(util.inspect(post));      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">util.inspect方法将对象转换为字符串,然后再res.end响应回网页端</span>
<span style="color: rgba(0, 0, 0, 1)">    });
}).listen(</span>3000);</pre>
</div>
<p>&nbsp;</p>
<h2>9、node.js操作MySQL数据库</h2>
<h3>9.1、连接MySQL数据库</h3>
<p>首先使用 npm 初始化项目,然后安装 MySQL 模块:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">npm init

npm install mysql</span></pre>
</div>
<p>创建一个 index.js 文件:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> mysql      = require('mysql'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> connection =<span style="color: rgba(0, 0, 0, 1)"> mysql.createConnection({
host   : </span>'localhost',    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">主机地址</span>
user   : 'root',         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">用户名</span>
password : '123456',       <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">密码</span>
database : 'test'          <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">数据库名</span>
<span style="color: rgba(0, 0, 0, 1)">});

connection.connect();    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">连接数据库</span>
<span style="color: rgba(0, 0, 0, 1)">
connection.query(</span>'SELECT 1 + 1 AS solution', <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (error, results, fields) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (error) <span style="color: rgba(0, 0, 255, 1)">throw</span><span style="color: rgba(0, 0, 0, 1)"> error;
console.log(</span>'The solution is: ', results.solution);
});</span></pre>
</div>
<p>&nbsp;</p>
<h3>9.2、数据库的基本操作(CURD)</h3>
<p>查询数据:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> mysql= require('mysql'<span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 0, 255, 1)">var</span> connection =<span style="color: rgba(0, 0, 0, 1)"> mysql.createConnection({   
host   : </span>'localhost'<span style="color: rgba(0, 0, 0, 1)">,      
user   : </span>'root'<span style="color: rgba(0, 0, 0, 1)">,            
password : </span>'123456'<span style="color: rgba(0, 0, 0, 1)">,      
port: </span>'3306'<span style="color: rgba(0, 0, 0, 1)">,                  
database: </span>'test'<span style="color: rgba(0, 0, 0, 1)">
});

connection.connect();

</span><span style="color: rgba(0, 0, 255, 1)">var</span>sql = 'SELECT * FROM websites'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">查</span>
connection.query(sql,<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (err, result) {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(err){
      console.log(</span>' - '<span style="color: rgba(0, 0, 0, 1)">,err.message);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
    }

    console.log(result);
});

connection.end();</span></pre>
</div>
<p>插入数据:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> mysql= require('mysql'<span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 0, 255, 1)">var</span> connection =<span style="color: rgba(0, 0, 0, 1)"> mysql.createConnection({   
host   : </span>'localhost'<span style="color: rgba(0, 0, 0, 1)">,      
user   : </span>'root'<span style="color: rgba(0, 0, 0, 1)">,            
password : </span>'123456'<span style="color: rgba(0, 0, 0, 1)">,      
port: </span>'3306'<span style="color: rgba(0, 0, 0, 1)">,                  
database: </span>'test'<span style="color: rgba(0, 0, 0, 1)">
});

connection.connect();

</span><span style="color: rgba(0, 0, 255, 1)">var</span>addSql = 'INSERT INTO websites(Id,name,url,alexa,country) VALUES(0,?,?,?,?)'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span>addSqlParams = ['菜鸟工具', 'https://c.runoob.com','23453', 'CN'<span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">增</span>
connection.query(addSql, addSqlParams, <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (err, result) {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)">(err){
      console.log(</span>' - '<span style="color: rgba(0, 0, 0, 1)">,err.message);
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
    }      

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">console.log('INSERT ID:',result.insertId);      </span>
    console.log('INSERT ID:'<span style="color: rgba(0, 0, 0, 1)">,result);      
});

connection.end();</span></pre>
</div>
<p>插入数据有两种写法:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">直接将插入值写在VALUE后面</span>
pool.query(INSERT INTO user ( id, username, PASSWORD, age, sex, permission, isDelete )VALUES( 4, "lijian", "123456", 18, 1, 0, 0 ),(err,result)=&gt;<span style="color: rgba(0, 0, 0, 1)">{
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(err) <span style="color: rgba(0, 0, 255, 1)">throw</span><span style="color: rgba(0, 0, 0, 1)"> err;
    console.log(result);
});

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">先写占位符,再在数据中写入插入值</span>
pool.query(INSERT INTO user VALUES(?,?,?,?,?,?,?),,(err,result)=&gt;<span style="color: rgba(0, 0, 0, 1)">{
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(err) <span style="color: rgba(0, 0, 255, 1)">throw</span><span style="color: rgba(0, 0, 0, 1)"> err;
    console.log(result);
});</span></pre>
</div>
<p>删除、修改操作跟上述大同小异,可参考:https://www.runoob.com/nodejs/nodejs-mysql.html</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/wenxuehai/p/14245530.html
頁: [1]
查看完整版本: Node.js的基本使用