本篇文章,讲述了一个很简单的上传图片(/start)到本地服务器,然后路由跳转到/upload.
写这个程序的目的是为了帮助理解HTTP的一些基本概念及node对于http api的实现以及程序的设计模式.
IP: 计算机之间的通信
TCP: 应用程序之间的通信
HTTP: 基于TCP实现的应用层协议,设计之初是为了提供一种HTML页面的发布和接收的方法,就是传输一些超文本(HyperText)的规则.

// 注:一些用到的基础,会在对应的代码前说明。下面先简单的介绍一下功能

当在浏览器中输入 http://localhost:8888/start 时,显示如下内容(有点丑,没写CSS…将就看吧):

选择文件:


点击Upload file

要解决如下几个问题:
1.服务器监听localhost,端口8888下,路径为/start的url
2.服务器处理该请求,并返回内容(通过http)
3.返回的内容对选择文件和Upload File做出反应

在此之前,需要做如下的准备: 根据依赖注入的思想,我们需要一个index.js文件来处理服务器和路由之间的关系.

index.js: 负责启动服务器,并向服务器传入路由和事件处理程序(事件处理程序可以参考《JavaScript高级程序设》P345)

// index.js
var server = require('./server');   // 服务器,监听浏览器发送的http请求
var route = require('./route');    // 路由,对不同路径进行不同的处理
var requestHandlers = require('./requestHandlers');    // 事件处理程序// 在index这一层,可以将requestHandlers做一些简单的处理
// 将事件处理程序对应到handle中,路径作为属性
var handle = {};
handle["/"] = requestHandlers.start;    // 如果值输入start就调用start的事件处理器
handle["/start"] = requestHandlers.start;
handle["/uoload"] = requestHandlers.uoload;
handle["/show"] = requestHandlers.show; // 调用启动服务器..
server.start(route, handle);

server服务器: 监听端口8888(会根据浏览器的请求HTTP生成一个请求路径),将请求路径(request.url)、求报文(resquest)、响应报文(response)、以及事件处理程序交给路由层

// server.js
var http = require('http');function start(route, handle) {// 服务器的事件处理程序 onRequestfunction onRequest(request , response) {var pathname = request.url;// 因为会多请求一个/favicon.ico(具体原因百度) , 故过滤掉它if (pathname === '/favicon.ico' ) {// 过滤掉...} else {  // 其他路由// 将请求路径交给路由层route(handle, pathname, response, request);}}// 创建服务器http.createServer(onRequest).listen(8888);
}// 到处start方法,供其他js使用
exports.start = start;// 注:在JS中函数可以作为参数,可以作为返回值,还可以作为变量赋值.具体可以参考函数式编程

route层: 根据服务器传入的检查事件处理程序中是否含有该路径,如果有则交给请求处理层,否则返回404响应报文

// route.js
function route(handle, pathname, response, request) {if( typeof handle[path] === 'function') {handle[pathname](response, request);} else {response.writeHead(404,{'Content-Type' : "text/plain" })response.write('404 Not Found');  // 可以自定义html的404页面返回response.end();}
}
exports.route = route;

请求处理层(requestHandlers): 对不同路劲的具体处理方式:start、upload、show。(后续可以根据需求拓展)

先分开来说明具体需求和实现,最后汇总
1.start: 显示一个上传的input框,和一个提交的按钮
// 注:上传的框引入了一个外部模块formidable 具体了解formidable

// start(这是讲解,后面汇总)
// start 会显示一个html页面,可以使用fs来写一个读取Html页面的函数getHTML
function getHTML(url) {let promise = new Promise(resolve, reject) {fs.readFile(url, (err, data) {if (!err) {resolve(data);} else {reject(err)}})return promise
}// 可以使用上面定义函数写start函数
function start(request, response) {let url = "./start.html"  // 最后会给出let html = getHTML(url);html.then((data) => {response.writeHead(200,{'Content-Type' : 'text/plain'});response.write(data);  // 可以接收buffer , stringresponse.end();}, (err) => {console.log(err);})
}

2.upload: 用于处理start页面传入的图片,将图片放入/temp文件夹下.重新命名为test.png,并将图片作为http响应报文的body部分传递给浏览器.浏览器根据img的src 访问找到图片显示出来.

function upload(request , response) {var form = new formidable.IncomingForm();// 这里涉及到一个cross-device问题.在结尾的参考文献中会给出form.uploadDir = "temp";form.parse(request, (err, fields, files) => {fs.renameSync(files.upload.path, "/temp/test.png");response.writeHead(200,{ 'Content-Type' : 'text/html'});response.write("received image:<br /> ");response.write("<img src='/show' />");response.end();})
}

3.show: 用于将本地的/temp/test.png显示在浏览器上.触发条件是<img src=’/show’ />.即触发了(/show路由,但是在请求url中还是localhost:8888/upload)

function show (request, response) {let url = "./temp/test.png";fs.readFile(url, 'binary', (err, file) => {if(err ) {response.writeHead(500, {'Content-Type' : 'text/plain'});response.write(err + '\n' );response.end();} else {response.writeHead(200, {'Content-Type' : 'image/jpg' });    // 告诉浏览器是个图片类型response.write(file, 'binary');response.end();}})
}

1+2+3 = requestHandlers.js:

// requestHandlers.js   (这样写的可维护性,拓展性更高)
var fs = require('fs'),formidable = require('formidable');// 根据url获取本地的html(buffer)
function getHTML(url) {let promise = new Promise((resolve, reject) => {fs.readFile(url, (err, data) => {if (!err) {resolve(data)} else {reject(data)}})})return promise;
}function start(response) {let url = './start.html';let html = getHTML(url);html.then((body) => {response.writeHead(200, { 'Content-Type': 'text/html' });response.write(body);response.end();}, (err) => {console.log(err);})
}function upload(response, request) {var form = new formidable.IncomingForm();form.uploadDir = 'temp';form.parse(request, (err, fields, files) => {fs.renameSync(files.upload.path, "./temp/test.png");response.writeHead(200, { "Content-Type": "text/html" });response.write("received image:<br />");response.write("<img src='/show' />");response.end();})
}function show(response) {let url = "./temp/test.png";fs.readFile(url, "binary", (err, file) => {if (err) {response.writeHead(500, { "Content-Type": "text/plain" });response.write(err + '\n');response.end();} else {response.writeHead(200, { "Content-Type": "image/jpg" });response.write(file, "binary");response.end();}})
}exports.start = start;
exports.upload = upload;
exports.show = show;

start.html

<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html" charset="utf-8">
</head><body><!-- 使用post方法将表单中的元素提交到相对路径下的upload中 --><form action="/upload" method="post" enctype="multipart/form-data"><input type="file" name="upload"><input type="submit" value="Upload file" /></form>
</body></html>

参考1: fs.renameSync报错的问题
参考2: Node入门

node --- 游走在客户端和服务器间的http相关推荐

  1. socket网络编程——基于socket通信实现对客户端与服务器间的文件互传

    客户端与服务器间的文件互传 基于socket的文件数据互传,将文件中所有的字符一一通过buf进行传递,为了更好地判断文件的 结束,通过添加文件结束标识符"#",当接收端接收到该字符 ...

  2. python3socket非阻塞_利用Python中SocketServer 实现客户端与服务器间非阻塞通信

    利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信. 首先,先了解下SocketServer模块中可供使用的类: BaseServer:包含服务器的核心功能与混合(mix-in ...

  3. pythontcp服务器如何关闭阻塞_利用Python中SocketServer 实现客户端与服务器间非阻塞通信...

    利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信. 首先,先了解下SocketServer模块中可供使用的类: BaseServer:包含服务器的核心功能与混合(mix-in ...

  4. python3socket非阻塞在linux里无效_利用Python中SocketServer实现客户端与服务器间非阻塞通信方法介绍...

    利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信 首先,先了解下SocketServer模块中可供使用的类: BaseServer:包含服务器的核心功能与混合(mix-in) ...

  5. VB6 通过winsock控件数组实现客户端和服务器多对一通信

    说明:我是在最近开发一个考试系统过程中搜索到上面文章的,它提供的思想非常实用.当然,这篇文章仅提供了一个基本思路,详细的实现在人民邮电出版社出版的<Visual Basic网络通信协议分析与应用 ...

  6. 一种即时通信数据传输方法、客户端、服务器及系统

    一种即时通信数据传输方法.客户端.服务器及系统  摘要 本发明实施例提供一种即时通信数据传输方法.客户端.服务器及系统,其中,方法可以包括:向服务器发送传输控制协议TCP连接建立请求,建立与所述服务器 ...

  7. 以太坊 node data write error_Node之 创建服务器与客户端

    阅读本文约需要6分钟 大家好,我是你们的导师,经常看我朋友圈的同学应该知道,我每天会在微信上给大家免费提供以下服务! 1.长期为你提供最优质的学习资源! 2.给你解决技术问题! 3.每天在朋友圈里分享 ...

  8. 基于随机游走Random Walk的图节点Node表示

    前言 在图中,如果能把节点表示成合适的数值,能做很多任务,例如节点分类,关系预测,聚类等等.如何把节点表示成计算机能看懂的数值目前也有很多方法,本文主要为大家介绍基于Random Walk的节点表示方 ...

  9. mfc客户端和服务器文件传输,mfc服务器客户端间传输文件

    mfc服务器客户端间传输文件 内容精选 换一换 华为云帮助中心,为用户提供产品简介.价格说明.购买指南.用户指南.API参考.最佳实践.常见问题.视频帮助等技术文档,帮助您快速上手使用华为云服务. 为 ...

最新文章

  1. SingleCellExperiment类使用
  2. 路由和远程访问---基本
  3. 第三章 PLSQL Developer 安装前oracleclient客户端的配置,在用plsql 连接oracle服务器
  4. 攻防世界Reverse第七题simple-unpack
  5. java设置text默认内容_Eclipse自定义内容辅助基于默认Java内容辅助结果
  6. mysql 开启innodb win版本_MySQL安装与启动——Windows系统下
  7. linux oracle 运维_Oracle查询当前的crs/has自启动状态实例教程
  8. Go程序:演示复数类型的用法
  9. 给RabbitMQ发送消息时,设置请求头Header。
  10. 优粮生活炒菜机器人_闫寒 - 外卖O2O「优粮生活」合伙人 | 到「在行」来约见我...
  11. 疑似 B 站后台源码泄露,ikun 潜入?
  12. springSecurity jwt 认证与鉴权及异常
  13. 联想G450 Linux wifi,联想g450无线网卡驱动,详细教您无线网卡安装教程
  14. origin免安装_美俏女剑士ORIGIN中文免安装版 11.4G
  15. anjuta 连接mysql_anjuta的基本使用方法(包括如何设置MYSQL)
  16. 微命令、微指令、微操作
  17. .xb文件腾讯云备份恢复
  18. C++程序员的发展前景,老程序员:早知道当初就学C++了!
  19. 1.11CSS的基本语法
  20. 武汉疫情 - 新型冠状病毒信息整理

热门文章

  1. 操作系统锁的实现方法有哪几种_「从入门到放弃-Java」并发编程-锁-synchronized...
  2. GPU Gems1 - 24 高质量的过滤
  3. 李宏毅机器学习课程11~~~为何要深?
  4. python——获取数据类型
  5. windows下解决mysql5中文乱码的问题
  6. Celery框架简单实例
  7. 过滤器 拦截器 区别
  8. 移动端输入框弹出键盘控制
  9. 为什么“三次握手,四次挥手”?
  10. JAVA取随机数,石头剪刀布实例