0

0

从0到1学习node(二)之搭建http服务器

大家讲道理

大家讲道理

发布时间:2017-01-24 15:40:40

|

1357人浏览过

|

来源于php中文网

原创

在上节的课前学习中,我们了解了一下不同模块规范之间的联系与区别。本节我们正式开始node的学习,首先我们从搭建一个http服务器,能运行简单的程序开始说起。

1. hello world

最经典的hello world。首先我们创建一个server.js来保存我们的代码:

console.log( 'hello world' );

在终端输入node server.js运行:

node server.js

终端就会输出 hello world 的字样。可是我们一个node服务器程序,总是要在浏览器上访问的呀,这里就要用到node里自带的http模块了:

var http = require('http'); // 引入http模块// 创建http服务器// request : 从浏览器带来的请求信息// response : 从服务器返回给浏览器的信息http.createServer(function(request, response){
    response.writeHead(200, {'content-type': 'text/plain'}); // 设置头部信息,输出text文本
    response.write('hello world'); // 输出到页面中的信息
    response.end(); // 返回结束}).listen(3000);console.log('server has started...');

我们再次在终端输入node server.js运行,终端里会有输出 server has started… 的字样,表示服务器已创建并正在运行,然后我们在浏览器上访问127.0.0.1:3000,就可以看到页面中输出了hello world

2. form表单

刚才我们只是在页面中输出了一段简单的文本,现在我们要在页面中呈现一个表单,可以让用户输入信息并进行提交:

// server.js
var http = require('http');

http.createServer(function(request, response){
var html = '\    \    \    \    \    
\

username :

\

password :

\

age :

\

\
\ \ '; response.writeHead(200, {'content-type': 'text/html'}); // 输出html头信息 response.write(html); // 将拼接的html字符串输出到页面中 response.end(); // 结束 }).listen(3000); console.log('server has started...');

修改server.js中的内容,重新运行:

node server.js

刷新页面后,我们发现页面中输出了3个文本框和1个提交按钮。因为我们的程序只是呈现页面,并没有做任何其他的处理,因此在页面中提交数据只是刷新当前页面。

注意: 我们每次修改node中的任何代码后,都要重新进行启动。

2.1 获取表单GET方式提交的数据

我们上面的代码中使用的是POST方式,不过这里要先讨论使用GET方式提交过来的数据,我们先不考虑数据的安全性,只是学习如何获取使用get方式提交过来的form表单数据,将post改为get,重新运行。

我们知道,使用get方式提交数据,会将数据作为URL参数传递过来,因此我们通过解析URL中的参数获取到数据,这里就用到了url模块中的方法:

// server.js
var http = require('http'),
url = require('url');

http.createServer(function(request, response){
    var html = '\        \        \        \        \        
\

username :

\

password :

\

age :

\

\
\ \ '; var query = url.parse( request.url, true ).query; if( query.submit ){ var data = '

back

'+ '

username:'+query.username+'

'+ '

password:'+query.password+'

'+ '

age:'+query.age+'

'; response.writeHead(200, {'content-type': 'text/html'}); response.write(data); }else{ response.writeHead(200, {'content-type': 'text/html'}); response.write(html); } response.end(); // 结束 }).listen(3000); console.log('server has started...');

我们再次运行提交后就能在页面中显示出数据了。

url.parse是用来解析URL字符串的,并返回解析后的URL对象。若我们只输出一下 url.parse(request.url) :

url.parse(request.url);
result:
Url {
    protocol: null,   
     slashes: null,   
      auth: null,    
      host: null,    
      port: null,    
      hostname: null,    
      hash: null,    
      search: '?username=111113&password=123&age=122&submit=submit',    
      query: 'username=111113&password=123&age=122&submit=submit',   
       pathname: '/',    
       path: '/?username=111113&password=123&age=122&submit=submit',    
       href: '/?username=111113&password=123&age=122&submit=submit'
       }

如果将第2个参数设置为true,则会将返回结果中的query属性解析为一个对象,其他属性不变;默认值为false,即query属性是一个字符串:

url.parse(request.url, true);result:Url {
...
query: {
    username: '111113',
    password: '123',
    age: '122',
    submit: 'submit' },
...
}

因此我们可以通过如下语句判断是否有提交数据并获取提交数据,然后再输出到中即可:

var query = url.parse( request.url, true ).query;
/*
{
    username: '111113',
    password: '123',
    age: '122',
    submit: 'submit'}
*/

2.2 获取表单POST方式提交的数据

现在我们使用post方式来提交数据。因为POST请求一般都比较“重” (用户可能会输入大量的内容),如果用阻塞的方式来处理处理,必然会导致用户操作的阻塞。因此node将post数据拆分为很多小的数据块,然后通过data事件(表示新的小数据块到达了)和end事件传递这些小数据块(表示所有的数据都已经接收完毕)。 所以,我们的思路应该是:在data事件中获取数据块,在end事件中操作数据。

// server.js
var http = require('http'),
querystring = require('querystring');

http.createServer(function(request, response){
    var html = '\        \        \        \        \        
\

username :

\

password :

\

age :

\

\
\ \ '; if( request.method.toLowerCase()=='post' ){ var postData = ''; request.addListener('data', function(chunk){ postData += chunk; }); request.addListener('end', function(){ var data = querystring.parse(postData); console.log( 'postData: '+postData ); console.log(data); var s = '

back

'+ '

username:'+data.username+'

'+ '

password:'+data.password+'

'+ '

age:'+data.age+'

'; response.writeHead(200, {'content-type': 'text/html'}); response.write(s); response.end(); }) }else{ response.writeHead(200, {'content-type': 'text/html'}); response.write(html); response.end(); } }).listen(3000); console.log('server has started...');

这段代码与上段代码项目,主要有的几个变化是:

  1. 不再引入url模块, 改用引入querystring模块。因为我们不再对URL进行操作了,也没必要引入了;

  2. 使用request.method.toLowerCase()=='post'判断当前是否有数据提交;

  3. 在data事件进行数据的拼接,在end事件中进行的处理;

    Singify
    Singify

    Singify是一款AI歌曲与音乐生成器。轻松生成原创歌曲、翻唱热门音乐、混音个性风格。

    下载
  4. response.end()写在了end事件内部,因为end事件是异步操作,因此必须得数据输出完成之后才能执行response.end()

我们在控制台中可以看出,postData是这样的一个字符串:

'username=123&password=123&age=23&submit=submit';

因此我们使用query.parse将postData解析为对象类型,以便获取提交过来的数据。

3. 路由

现在我们所有的逻辑都是在根目录下进行的,没有按照url区分,这里我们按照功能进行路由拆分。以上面的post请求为例,我们可以拆分为:页面初始化和form提交后的处理。

页面初始化:

// starter.js  页面初始化

function start(request, response){
    var html = '\        \        \        \        \        
\

username :

\

password :

\

age :

\

\
\ \ '; response.writeHead(200, {"Content-Type":"text/html"}); response.write( html ); response.end(); } exports.start = start;

展示获取的数据:

// uploader.js 展示获取的数据var querystring = require('querystring');function upload(request, response){    var postData = '';

    request.addListener('data', function(chunk){
      postData += chunk;
    });
    
    request.addListener('end', function(){        var data = querystring.parse(postData);        console.log( 'postData: '+postData );        console.log(data);        var s = '

back

'+ '

username:'+data.username+'

'+ '

password:'+data.password+'

'+ '

age:'+data.age+'

'; response.writeHead(200, {'content-type': 'text/html'}); response.write(s); response.end(); }) } exports.upload = upload;

然后在server.js中进行路由选择

// server.jsvar http = require('http'),
url = require('url');

http.createServer(function(request, response){    var pathname = url.parse(request.url).pathname;    console.log(pathname);
    response.end();
}).listen(3000);console.log('server has started...');

我们任意改变URL地址,会看到输出的每个地址的pathname(忽略/favicon.ico):

http://127.0.0.1:3000/ // 输出: /
http://127.0.0.1:3000/show/ // 输出: /show/
http://127.0.0.1:3000/show/img/ // 输出: /show/img/
http://127.0.0.1:3000/show/?username=wenzi // 输出: /show/

因此我们就根据pathname进行路由,对路由进行方法映射:

// server.jsvar http = require('http'),
url = require('url'),
starter = require('./starter'),
uploader = require('./uploader');

http.createServer(function(request, response){    var pathname = url.parse(request.url).pathname;    var routeurl = {        '/' : starter.start,        '/show' : uploader.upload
    }    if( typeof routeurl[pathname]=== 'function' ){
        routeurl[pathname](request, response);
    }else{        console.log('404 not found!');
        response.end();
    }
}).listen(3000);console.log('server has started...');

如果匹配到路由 / ,则执行 starter.start(request, response) ;如果匹配到路由 /show ,则执行 uploader.upload(request, response) 。如果都没匹配到,则显示404。

4. 图片上传并显示

在上面我们已经能成功提交数据了,这里来讲解如何进行图片上传并显示。使用node自带的模块处理起来非常的麻烦,这里我们使用别人已经开发好的formidable模块进行编写,它对解析上传的文件数据做了很好的抽象。

npm install formidable --save-dev

在starter.js中,我们添加上file控件:

// starter.js
function start(request, response){
    var html = '\
        \
        \
        \
        \
        
\

file :

\

\
\ \ '; response.writeHead(200, {"Content-Type":"text/html"}); response.write( html ); response.end(); } exports.start = start;

4.1 图片上传

首先我们进行的是图片上传操作,首先我们要确保当前目录中存在tmp和img目录。在 uploader.js 中:

// uploader.jsvar formidable = require('formidable'),
util = require('util'),
fs = require('fs');function upload(request, response){    if( request.method.toLowerCase()=='post' ){        var form = new formidable.IncomingForm();

        form.uploadDir = './tmp/';
        form.parse(request, function(err, fields, files) {            var oldname = files.upload.name,
                newname = Date.now() + oldname.substr(oldname.lastIndexOf('.'));
            fs.renameSync(files.upload.path, "./img/"+newname ); // 上传到 img 目录

            response.writeHead(200, {'content-type': 'text/plain'});
            response.write('received upload:\n\n');
            response.end(util.inspect({fields: fields, files: files}));
        });        return;
    }
}
exports.upload = upload;

我们上传图片后跳转到upload路径,然后显示出相应的信息:

received upload:

{
    fields: { // 其他控件,如input, textarea等
    submit: 'submit'},
files:{ // file控件
    upload:{
            domain: null,
            _events: {},
            _maxListeners: undefined,
            size: 5097,
            path: 'tmp\\upload_b1f7c3e83af224e9f3a020958cde5dcd',
            name: 'chrome.png',
            type: 'image/png',
            hash: null,
            lastModifiedDate: Thu Jan 12 2017 23:09:50 GMT+0800 (中国标准时间),
            _writeStream: [Object]
        }
    }
}

我们再查看img目录时,就会发现我们刚才上传的照片了。

4.2 图片显示

将图片上传到服务器后,怎样才能把图片显示在浏览器上呢。这里我们就使用到了fs模块来读取文件,创建一个shower.js来专门展示图片:

// shower.jsvar fs = require('fs'),
url = require('url');function show(request, response){    var query = url.parse(request.url, true).query,
        imgurl = query.src;    // 读取图片并进行输出
    // 这里读取链接中的src参数,指定读取哪张图片  /show?src=1484234660592.png
    fs.readFile('./img/'+imgurl, "binary", function(err, file){         if(err) throw err;
        response.writeHead(200, {"Content-Type": "image/png"});
        response.write(file, "binary");
        response.end();
    })
}
exports.show = show;

然后在 server.js 中添加上 show 的路由映射:

var routeurl = {  
  '/' : starter.start,   
   '/upload' : uploader.upload,  
   '/show' : shower.show 
   // 添加
   };


最后在 upload.js 中进行图片的引用:

form.parse(request, function(err, fields, files) {    var oldname = files.upload.name,
        newname = Date.now() + oldname.substr(oldname.lastIndexOf('.'));
    fs.renameSync(files.upload.path, "./img/"+newname ); // 同步上传图片

    response.writeHead(200, {'content-type': 'text/html'});    var s = '

back

@@##@@

'; // 显示刚才的图片 response.write(s); response.end(); });

5. 综合

刚才学习了上传数据和上传图片,这里我们将其综合一下,拟定一个题目:“设定用户名密码,并上传头像”。希望可以自己实现一下。

6. 接口的实现

在第2部分学习了GET和POST请求,那么在这里写一个简单json或jsonp接口应该不是什么难事儿了吧。

创建一个 inter.js :

// inter.jsvar url = require('url');function init(request, response){    if( request.method.toLowerCase()=='get' ){        var query = url.parse(request.url, true).query;        var data = {"code":0, "msg":"success", "data":[{"username":"wenzi", "age":26}, {"username":"bing", "age":25}]};        if( query && query.callback ){            // jsonp
            response.end( query.callback + '(' + JSON.stringify(data) + ')' );
         }else{            // json
            response.end( JSON.stringify(data) );
        }
    }
}
exports.init = init;

在server中添加inter的引用和路由映射:

var routeurl = {    '/' : starter.start,    '/upload' : uploader.upload,    '/show' : shower.show,    '/inter' : inter.init // 添加};

然后对 http://127.0.0.1:3000/inter 进行json请求或jsonp请求即可。

7. 总结

这节还是写了不少的内容,最核心的就是讲解如何搭建一个简单的http服务器,进行数据和图片的提交与处理,在最后稍微讲了下接口的编写,后面有机会的话,会再具体讲解下接口的编写。


从0到1学习node(二)之搭建http服务器

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

15

2026.01.29

clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址
clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址

clawdbot龙虾机器人官网入口:https://clawd.bot/,clawdbot ai是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

12

2026.01.29

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

8

2026.01.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

550

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

197

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

331

2026.01.28

php怎么写接口教程
php怎么写接口教程

本合集涵盖PHP接口开发基础、RESTful API设计、数据交互与安全处理等实用教程,助你快速掌握PHP接口编写技巧。阅读专题下面的文章了解更多详细内容。

11

2026.01.28

php中文乱码如何解决
php中文乱码如何解决

本文整理了php中文乱码如何解决及解决方法,阅读节专题下面的文章了解更多详细内容。

16

2026.01.28

Java 消息队列与异步架构实战
Java 消息队列与异步架构实战

本专题系统讲解 Java 在消息队列与异步系统架构中的核心应用,涵盖消息队列基本原理、Kafka 与 RabbitMQ 的使用场景对比、生产者与消费者模型、消息可靠性与顺序性保障、重复消费与幂等处理,以及在高并发系统中的异步解耦设计。通过实战案例,帮助学习者掌握 使用 Java 构建高吞吐、高可靠异步消息系统的完整思路。

11

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
HTML5/CSS3/JavaScript/ES6入门课程
HTML5/CSS3/JavaScript/ES6入门课程

共102课时 | 6.8万人学习

前端基础到实战(HTML5+CSS3+ES6+NPM)
前端基础到实战(HTML5+CSS3+ES6+NPM)

共162课时 | 19.1万人学习

第二十二期_前端开发
第二十二期_前端开发

共119课时 | 12.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号