CoffeeScript 基本的 HTTP 服務(wù)器

2022-06-29 17:13 更新

基本的 HTTP 服務(wù)器

問題

你想在網(wǎng)絡(luò)上創(chuàng)建一個HTTP服務(wù)器。在這個方法中,我們將逐步從最小的服務(wù)器成為一個功能鍵值存儲。

解決方案

我們將使用node.js HTTP庫并在Coffeescript中創(chuàng)建最簡單的web服務(wù)器。

開始 'hi\n'

我們可以通過導(dǎo)入node.js HTTP模塊開始。這會包含createServer,一個簡單的請求處理程序返回HTTP服務(wù)器。我們可以使用該服務(wù)器監(jiān)聽TCP端口。

http = require 'http'
server = http.createServer (req, res) -> res.end 'hi\n'
server.listen 8000

要運行這個例子,只需放在一個文件中并運行它。你可以用ctrl-c終止它。我們可以使用curl命令測試它,可用在大多數(shù)*nix平臺:

$ curl -D - http://localhost:8000/
HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked

hi

發(fā)生什么了?

讓我們一點點來反饋服務(wù)器上發(fā)生的事情。這時,我們可以友好的對待用戶并提供他們一些HTTP頭文件。

http = require 'http'

server = http.createServer (req, res) ->
    console.log req.method, req.url
    data = 'hi\n'
    res.writeHead 200,
        'Content-Type':     'text/plain'
        'Content-Length':   data.length
    res.end data

server.listen 8000

再次嘗試訪問它,但是這一次使用不同的URL路徑,比如http://localhost:8000/coffee。你會看到這樣的服務(wù)器控制臺:

$ coffee http-server.coffee 
GET /
GET /coffee
GET /user/1337

得到的東西

假如我們的網(wǎng)絡(luò)服務(wù)器能夠保存一些數(shù)據(jù)會怎么樣?我們將在通過GET方法請求檢索的元素中設(shè)法想出一個簡單的鍵值存儲。并提供一個關(guān)鍵路徑,服務(wù)器將請求返回相應(yīng)的值,如果不存在則返回404錯誤。

http = require 'http'

store = # we'll use a simple object as our store
    foo:    'bar'
    coffee: 'script'

server = http.createServer (req, res) ->
    console.log req.method, req.url

    value = store[req.url[1..]]

    if not value
        res.writeHead 404
    else
        res.writeHead 200,
            'Content-Type': 'text/plain'
            'Content-Length': value.length + 1
        res.write value + '\n'

    res.end()

server.listen 8000

我們可以試試幾種url,看看它們?nèi)绾位貞?yīng):

$ curl -D - http://localhost:8000/coffee
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 7
Connection: keep-alive

script

$ curl -D - http://localhost:8000/oops
HTTP/1.1 404 Not Found
Connection: keep-alive
Transfer-Encoding: chunked

使用你的頭文件

text/plain是站不住腳的。如果我們使用application/json或text/xml會怎么樣?同時,我們的存儲檢索過程也可以用一點重構(gòu)——一些異常的拋出&處理怎么樣? 來看看我們能想出什么:

http = require 'http'

# known mime types
[any, json, xml] = ['*/*', 'application/json', 'text/xml']

# gets a value from the db in format [value, contentType]
get = (store, key, format) ->
    value = store[key]
    throw 'Unknown key' if not value
    switch format
        when any, json then [JSON.stringify({ key: key, value: value }), json]
        when xml then ["<key>#{ key }</key>\n<value>#{ value }</value>", xml]
        else throw 'Unknown format'

store =
    foo:    'bar'
    coffee: 'script'

server = http.createServer (req, res) ->
    console.log req.method, req.url

    try
        key = req.url[1..]
        [value, contentType] = get store, key, req.headers.accept
        code = 200
    catch error
        contentType = 'text/plain'
        value = error
        code = 404

    res.writeHead code,
        'Content-Type': contentType
        'Content-Length': value.length + 1
    res.write value + '\n'
    res.end()

server.listen 8000

這個服務(wù)器仍然會返回一個匹配給定鍵的值,如果不存在則返回404錯誤。但它根據(jù)標頭Accept將響應(yīng)在JSON或XML結(jié)構(gòu)中??捎H眼看一下:

$ curl http://localhost:8000/
Unknown key

$ curl http://localhost:8000/coffee
{"key":"coffee","value":"script"}

$ curl -H "Accept: text/xml" http://localhost:8000/coffee
<key>coffee</key>
<value>script</value>

$ curl -H "Accept: image/png" http://localhost:8000/coffee
Unknown format

你需要有所返回

我們的最后一步是提供客戶端存儲數(shù)據(jù)的能力。我們將通過監(jiān)聽POST請求來保持RESTiness。

http = require 'http'

# known mime types
[any, json, xml] = ['*/*', 'application/json', 'text/xml']

# gets a value from the db in format [value, contentType]
get = (store, key, format) ->
    value = store[key]
    throw 'Unknown key' if not value
    switch format
        when any, json then [JSON.stringify({ key: key, value: value }), json]
        when xml then ["<key>#{ key }</key>\n<value>#{ value }</value>", xml]
        else throw 'Unknown format'

# puts a value in the db
put = (store, key, value) ->
    throw 'Invalid key' if not key or key is ''
    store[key] = value

store =
    foo:    'bar'
    coffee: 'script'

# helper function that responds to the client
respond = (res, code, contentType, data) ->
    res.writeHead code,
        'Content-Type': contentType
        'Content-Length': data.length
    res.write data
    res.end()

server = http.createServer (req, res) ->
    console.log req.method, req.url
    key = req.url[1..]
    contentType = 'text/plain'
    code = 404

    switch req.method
        when 'GET'
            try
                [value, contentType] = get store, key, req.headers.accept
                code = 200
            catch error
                value = error
            respond res, code, contentType, value + '\n'

        when 'POST'
            value = ''
            req.on 'data', (chunk) -> value += chunk
            req.on 'end', () ->
                try
                    put store, key, value
                    value = ''
                    code = 200
                catch error
                    value = error + '\n'
                respond res, code, contentType, value

server.listen 8000

在一個POST請求中注意數(shù)據(jù)是如何接收的。通過在“數(shù)據(jù)”和“結(jié)束”請求對象的事件中附上一些處理程序,我們最終能夠從客戶端緩沖和保存數(shù)據(jù)。

$ curl -D - http://localhost:8000/cookie
HTTP/1.1 404 Not Found # ...
Unknown key

$ curl -D - -d "monster" http://localhost:8000/cookie
HTTP/1.1 200 OK # ...

$ curl -D - http://localhost:8000/cookie
HTTP/1.1 200 OK # ...
{"key":"cookie","value":"monster"}

討論

給http.createServer一個函數(shù) (request,response) - >…… 它將返回一個服務(wù)器對象,我們可以用它來監(jiān)聽一個端口。讓服務(wù)器與request和response對象交互。使用server.listen 8000監(jiān)聽端口8000。

在這個問題上的API和整體信息,參考node.js httphttps文檔頁面。此外,HTTP spec可能派上用場。

練習

在服務(wù)器和開發(fā)人員之間創(chuàng)建一個層,允許開發(fā)人員做類似的事情:

server = layer.createServer
    'GET /': (req, res) ->
        ...
    'GET /page': (req, res) ->
        ...
    'PUT /image': (req, res) ->
        ...
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號