node.js之前后端交互小样例

我们写个表单,来看下基于node.js的前后端交互。

先说明要做的事情: 表单中输入数据提交后传给服务端,服务端收到HTTP请求后响应,传送数据给客户端,客户端输出显示(这里不写模板渲染了)

首先我们写个html文件建立一个表单,程序如下:

home.html




    
    主页


    

页面非常简单,不过要小心,这里的按钮是用input 设置type='button'完成的。

直接使用button可能会出错,单击按钮自动刷新。

见讨论:http://bbs.csdn.net/topics/390307663

之后我们写服务端程序,在浏览器输入url后返回这个页面:

server.js

var http = require('http')
var fs = require('fs')

var server =  new http.Server()

function sendfile( res, abspath, data ) {
    res.writeHead(
        200,
        {'content-type': 'text/html'}
    )
    res.end( data )
}

function serverStatic(res,abspath) {
    fs.readFile( abspath, function (err,data){
        sendfile( res, abspath, data )
    })
}
server.on( 'request', function (req, res) {
  console.log('-----接收到请求-----')
  serverStatic(res,'./home.html')
})

server.listen(2500)

下面对上面的程序做出说明:
首先我们需要导入http模块和fs模块。fs模块是用来提供文件系统相关功能的。
先建立一个Http.Server类实例,用该实例进行服务端操作。看下官方文档
http://nodejs.cn/api/http.html#http_class_http_server
官网第一句:该类继承自 net.Server,且具有以下额外的事件:
这里我们用到的是request事件,对于request事件,提供一个监听函数,这个监听函数有两个参数
request,response。不要把监听函数里的request对象和request事件混为一谈,request事件里的request是事件名称

node.js之前后端交互小样例_第1张图片

request事件的监听函数中的request对象是http.IncomingMessage实例,http.IncomingMessage是个可读流,数据从外部流到node,
你可以读取里面的数据,可读流可以自动读取(on或者pipe),也可以手动读取(read)。
request事件的监听函数中的response对象是http.ServerPonse实例,用官网里的话说http.ServerPons这个类实现了(而不是继承自)可写流 接口。
总结一下:在node是服务端的时候,req是从客户端发起的,是可读流,res是从node响应的,是可写流。
之后我们再看下文档对http.ServerResponse 类的描述
该对象在 HTTP 服务器内部被创建。 它作为第二个参数被传入 'request' 事件。
它作为第二个参数被传入‘request’事件也就是说它被作为‘request’事件的监听函数的第二个参数传入。server.on( 'request', function (req, res) {} )代码中的res就是http.ServerResponse类实例。
http.ServerResponse类有个方法,end方法,如下:

node.js之前后端交互小样例_第2张图片

下面我们看使用fs模块获取文件内容
我们上管网看下如何使用fs模块读取硬盘文件
http://nodejs.cn/api/fs.html#fs_fs_readfile_path_options_callback

node.js之前后端交互小样例_第3张图片

fs.readFile( abspath [,options], callback )有三个参数,其中第二个参数options参数可选, 第三个参数callback是回调函数
第一个参数是文件名或者文件描述符,可以传入string,url,buffer,interager类型的值给path,这里我们选的是绝对路径..
回调函数有两个参数,回调有两个参数 (err, data),其中 data 是文件的内容。
这样使用fs.readFile可以获取文件内容了。然后我们还要将文件内容作为响应的数据响应。因此需要这句res.end( data ),data就是文件内容。
总结一下代码思路,fs获取home.html文件内容data,之后响应以data返回.
至此输入url获取页面已经成功了,之后要做的就是发送POST请求,服务端获取请求的数据
我们获取点击按钮获取input的value的值将其发送给服务端,发起请求直接使用xhr对象即可,详细的见js高级教程

直接给出代码:

var button = document.getElementById("login")
            var xhr = new XMLHttpRequest()
            var handler = function(event) {//点击后获取input的值并发送
                var value = document.getElementById("inputName").value
//                console.log(value)
                xhr.open('post','/',true)//启动请求,url可以是相对于执行代码的当前页面
                xhr.send( value )
            }

button.addEventListener('click', handler )


为了接收post请求,修改server.on(  'request',  callback ),代码如下

server.on( 'request', function (req, res) {
  console.log('-----接收到请求-----')
    //res.end('hello')
   serverStatic(res,'./home.html')
    if( req.method=='POST' ){
      //console.log(req)
       console.log(req.rawHeaders)
        var data = ""
        req.on("data",function(chunk){
            data += chunk
        })
        req.on("end",function(){
           // console.log(data)
            res.writeHead(
                200,{'Content-Type':'text/plain'}
            )
             res.end('响应数据: '+data)
        })
    }
})

对上面代码做些说明,官网有下面的话:

http.IncomingMessage 类

查看英文版 / 参与翻译

IncomingMessage 对象由 http.Server 或 http.ClientRequest 创建,并作为第一个参数分别递给 'request' 和 'response' 事件。 它可以用来访问响应状态、消息头、以及数据。

它实现了 可读流 接口,还有以下额外的事件、方法、以及属性

注意最后一句: 它实现了 可读流 接口,还有以下额外的事件、方法、以及属性

我们看下可写流:

http://nodejs.cn/api/stream.html#stream_event_data
可写流有一个data事件
'data' 事件#

查看英文版 / 参与翻译

  • chunk  |  |  数据片段。对于非对象模式的可读流,这是一个字符串或者 Buffer。 对于对象模式的可读流,这可以是除 null 以外的任意类型 JavaScript 值。

'data' 事件会在流将数据传递给消费者时触发。当流转换到 flowing 模式时会触发该事件。调用 readable.pipe(), readable.resume() 方法,或为 'data'事件添加回调可以将流转换到 flowing 模式。 'data' 事件也会在调用 readable.read() 方法并有数据返回时触发。

在没有明确暂停的流上添加 'data' 事件监听会将流转换为 flowing 模式。 数据会在可用时尽快传递给下个流程。

如果调用 readable.setEncoding() 方法明确为流指定了默认编码,回调函数将接收到一个字符串,否则接收到的数据将是一个 Buffer 实例。

const readable = getReadableStreamSomehow();
readable.on('data', (chunk) => {
  console.log(`Received ${chunk.length} bytes of data.`);
});

是的。我们就是利用可写流data事件获取post请求内容的。 'data'  事件会在流将数据传递给消费者时触发,对应的监听函数中的chunk是数据片段,因为消息是一段一段发送的。消息发送完成后,流中无数据可供消费,触发end事件
'end' 事件#

查看英文版 / 参与翻译

'end' 事件将在流中再没有数据可供消费时触发。

触发end事件后,将拼接好的数据作为响应的一部分发送。


最后一步,客户端收到需要响应后输出,在home.html中添加如下代码即可:

xhr.onreadystatechange = function () {
                if( xhr.readyState==4  ){//已经接收全部响应数据
                    if( (xhr.status>=200&&xhr.status<300) || xhr.status==304 ){
                        console.log( '-----请求并响应成功------' )
                        console.log(xhr.responseText)
                        console.log( '-----请求并响应成功------' )
                    }else{
                        console.log( "请求未成功: " + xhr.status )
                    }
                }
            }

            xhr.onreadystatechange()

最后给出完整的代码:

home.html




    
    主页


    

server.js

var http = require('http')
var fs = require('fs')

var server =  new http.Server()

function sendfile( res, abspath, data ) {
    res.writeHead(
        200,
        {'content-type': 'text/html'}
    )
    res.end( data )
}

function serverStatic(res,abspath) {
    fs.readFile( abspath, function (err,data){
        sendfile( res, abspath, data )
    })
}

server.on( 'request', function (req, res) {
  console.log('-----接收到请求-----')
    //res.end('hello')
   serverStatic(res,'./home.html')
    if( req.method=='POST' ){
      //console.log(req)
       console.log(req.rawHeaders)
        var data = ""
        req.on("data",function(chunk){
            data += chunk
        })
        req.on("end",function(){
           // console.log(data)
            res.writeHead(
                200,{'Content-Type':'text/plain'}
            )
             res.end('响应数据: '+data)
        })
    }
})

server.listen(2500)




参考 js高级教程

        node.js官网

流:https://segmentfault.com/a/1190000000519006?share_user=1030000004603185

 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
  
 
 

你可能感兴趣的:(node.js)