真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何讓deno支持HTTP服務(wù)

這篇文章主要介紹“如何讓deno支持HTTP服務(wù)”,在日常操作中,相信很多人在如何讓deno支持HTTP服務(wù)問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”如何讓deno支持HTTP服務(wù)”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

“專業(yè)、務(wù)實(shí)、高效、創(chuàng)新、把客戶的事當(dāng)成自己的事”是我們每一個(gè)人一直以來堅(jiān)持追求的企業(yè)文化。 成都創(chuàng)新互聯(lián)是您可以信賴的網(wǎng)站建設(shè)服務(wù)商、專業(yè)的互聯(lián)網(wǎng)服務(wù)提供商! 專注于網(wǎng)站設(shè)計(jì)制作、做網(wǎng)站、軟件開發(fā)、設(shè)計(jì)服務(wù)業(yè)務(wù)。我們始終堅(jiān)持以客戶需求為導(dǎo)向,結(jié)合用戶體驗(yàn)與視覺傳達(dá),提供有針對(duì)性的項(xiàng)目解決方案,提供專業(yè)性的建議,創(chuàng)新互聯(lián)建站將不斷地超越自我,追逐市場(chǎng),引領(lǐng)市場(chǎng)!

現(xiàn)在的 deno 只支持很少的幾個(gè)功能, 并不支持搭建 HTTP 服務(wù), 如果想要用 deno 搭建 HTTP 服務(wù)要怎么辦呢?

只能自己進(jìn)行開發(fā)支持

代碼如下:

// helloServer.ts

import { Request, Response, createHttpServer } from "deno";

const server = createHttpServer((req: Request, res: Response) => {

  res.write(——[${req.method}] ${req.path} Hello world!——);

  res.end();

});

server.listen(3000);

上面是我們期望創(chuàng)建服務(wù)器的代碼, 接下來我們根據(jù)這段代碼一點(diǎn)點(diǎn)實(shí)現(xiàn)

Request, Response, createHttpServer

上面說過, deno 現(xiàn)在并沒有這些類和方法, 我們要構(gòu)建這些對(duì)象和方法。

注: 這里并不是要寫一個(gè)功能完善的模塊, 有很多東西我都會(huì)省略掉

// http.ts

import { main as pb } from "./msg.pb";

import { pubInternal, sub } from "./dispatch";

const enc = new TextEncoder();

const servers: {[key: number]: HttpServer} = {};

export class Request {

  method: string;

  path: string;

  constructor(msg: pb.Msg) {

    this.path = msg.httpReqPath;

    this.method = msg.httpReqMethod;

  }

}

export class Response{

  requestChannel: string;

  constructor(msg: pb.Msg) {

    this.requestChannel = ——http/${msg.httpReqId}——;

  }

}

let serverId = 0;

export class HttpServer {

  port: number;

  private id: number;

  private requestListener: (req: Request, res: Response) => void;

  constructor(requestListener: (req: Request, res: Response) => void) {

    this.requestListener = requestListener;

    this.id = serverId ++;

    servers[this.id] = this;

  }

}

export function createHttpServer(

  requestListener: (req: Request, res: Response) => void

): HttpServer {

  const server = new HttpServer(requestListener);

  return server;

}

在根目錄創(chuàng)建 http.ts , 在其中進(jìn)行定義。

Request 中有 method、path 兩個(gè)屬性, 簡(jiǎn)單起見, 瀏覽器請(qǐng)求中還有 body、header 等等其他實(shí)際中會(huì)用到的屬性我都忽略了。

Response 中 requestChannel 是用于通過 deno 訂閱/發(fā)布模式返回結(jié)果的, 后面能看到具體什么用。

HttpServer 中包括綁定的端口 port, 在構(gòu)造函數(shù)中, 生成對(duì) HttpServer 生成實(shí)例進(jìn)行標(biāo)識(shí)的 id, 及綁定對(duì)請(qǐng)求進(jìn)行處理的函數(shù) requestListener。

方法 createHttpServer 則是用 requestListener 創(chuàng)建 server 實(shí)例

server.listen

在有了 HttpServer 也綁定了 requestListenner 之后, 要監(jiān)聽端口

// http.ts

...

export class HttpServer {

  ...

  listen(port: number) {

    this.port = port;

    pubInternal("http", {

      command: pb.Msg.Command.HTTP_SERVER_LISTEN,

      httpListenPort: port,

      httpListenId: this.id

    });

  }

}

...

其中, pubInternal 方法需要兩個(gè)參數(shù) channel 和 msgObj, 上面的代碼就是將監(jiān)聽端口命令及所需的配置發(fā)布到 Golang 代碼中 http 這個(gè)頻道。

// msg.proto

...

message Msg {

  enum Command {

    ...

    HTTP_RES_WRITE = 14;

    HTTP_RES_END = 15;

    HTTP_SERVER_LISTEN = 16;

  }

  ...

  // HTTP

  int32 http_listen_port = 140;

  int32 http_listen_id = 141;

  bytes http_res_write_data = 142;

  int32 http_server_id = 143;

  string http_req_path = 144;

  string http_req_method = 145;

  int32 http_req_id = 146;

}

...

在 msg.proto 文件(protobuf 的定義文件)中對(duì)需要用到的 Command 以及 Msg 的屬性進(jìn)行定義, 需要注意的是, 屬性值需要使用下劃線命名, 在編譯 deno 時(shí)會(huì)會(huì)根據(jù)這個(gè)文件生成對(duì)應(yīng)的 msg.pb.d.ts、msg.pb.js 及 msg.pb.go 分別讓 ts 及 Golang 代碼使用, 這里對(duì)后續(xù)需要用到的定義都展示了, 后面不再贅述。

// http.go

package deno

import (

    "fmt"

    "net/http"

    "github.com/golang/protobuf/proto"

)

var servers = make(map[int32]*http.Server)

func InitHTTP() {

    Sub("http", func(buf []byte) []byte {

        msg := &Msg{}

        check(proto.Unmarshal(buf, msg))

        switch msg.Command {

        case Msg_HTTP_SERVER_LISTEN:

            httpListen(msg.HttpListenId, msg.HttpListenPort)

        default:

            panic("[http] unsupport message " + string(buf))

        }

        return nil

    })

}

func httpListen(serverID int32, port int32) {

    handler := buildHTTPHandler(serverID)

    server := &http.Server{

        Addr:    fmt.Sprintf(":%d", port),

        Handler: http.HandlerFunc(handler),

    }

    servers[serverID] = server

    wg.Add(1)

    go func() {

        server.ListenAndServe()

        wg.Done()

    }()

}

同樣在根目錄創(chuàng)建 http.go文件。

InitHTTP 中訂閱 http channel, 在傳入的 msg.command 為 Msg_HTTP_SERVER_LISTEN 時(shí)調(diào)用 httpListen 進(jìn)行端口監(jiān)聽(還記得之前 msg.proto 中定義的枚舉 Command 么, 在生成的 msg.proto.go 中會(huì)加上 Msg 前綴)。

httpListen 中用模塊 net/http 新建了一個(gè) httpServer, 對(duì)端口進(jìn)行監(jiān)聽, 其中 Handler 后面再說。

wg 是個(gè) sync.WaitGroup, 在 dispatch.go 中保證調(diào)度任務(wù)完成.

請(qǐng)求到來

在上面的代碼中已經(jīng)成功創(chuàng)建了 httpServer, 接下來瀏覽器發(fā)送 HTTP請(qǐng)求來到 http.go 中新建的 server 時(shí), 需要將請(qǐng)求轉(zhuǎn)交給 ts 代碼中定義的 requestListener 進(jìn)行響應(yīng)。

// http.go

...

var requestID int32 = 0

func buildHTTPHandler(serverID int32) func(writer http.ResponseWriter, req *http.Request) {

    return func(writer http.ResponseWriter, req *http.Request) {

        requestID++

        id, requestChan := requestID, fmt.Sprintf("http/%d", requestID)

        done := make(chan bool)

        Sub(requestChan, func(buf []byte) []byte {

            msg := &Msg{}

            proto.Unmarshal(buf, msg)

            switch msg.Command {

            case Msg_HTTP_RES_WRITE:

                writer.Write(msg.HttpResWriteData)

            case Msg_HTTP_RES_END:

                done <- true

            }

            return nil

        })

        msg := &Msg{

            HttpReqId:     id,

            HttpServerId:  serverID,

            HttpReqPath:   req.URL.Path,

            HttpReqMethod: req.Method,

        }

        go PubMsg("http", msg)

        <-done

    }

}

buildHTTPHandler 會(huì)生成個(gè) Handler 接收請(qǐng)求, 對(duì)每個(gè)請(qǐng)求生成 requestChan 及 id。

訂閱 requestChan 接收 ts 代碼中 requestListener 處理請(qǐng)求后返回的結(jié)果, 在 msg.Command 為 Msg_HTTP_RES_WRITE 寫入返回的 body, 而 Msg_HTTP_RES_END 返回結(jié)果給瀏覽器。

通過 PubMsg 可以將構(gòu)造出的 msg 傳遞給 ts 代碼, 這里需要 ts 代碼對(duì) http 進(jìn)行訂閱, 接收 msg。

// http.ts

...

const servers: {[key: number]: HttpServer} = {};

export function initHttp() {

  sub("http", (payload: Uint8Array) => {

    const msg = pb.Msg.decode(payload);

    const id = msg.httpServerId;

    const server = servers[id];

    server.onMsg(msg);

  });

}

...

export class HttpServer {

  ...

  onMsg(msg: pb.Msg) {

    const req = new Request(msg);

    const res = new Response(msg);

    this.requestListener(req, res);

  }

}

...

這里在初始化 initHttp 中, 訂閱了http, 得到之前 Golang 代碼傳遞過來的 msg, 獲取對(duì)應(yīng)的 server, 觸發(fā)對(duì)應(yīng) onMsg。

onMsg 中根據(jù) msg 構(gòu)建 Request 和 Response 的實(shí)例, 傳遞給 createHttpServer 時(shí)的處理函數(shù) requestListener。

在處理函數(shù)中調(diào)用了 res.write 和 res.end, 同樣需要在 type.ts 里進(jìn)行定義。

// http.ts

...

export class Response{

  ...

  write(data: string) {

    pubInternal(this.requestChannel, {

      command: pb.Msg.Command.HTTP_RES_WRITE,

      httpResWriteData: enc.encode(data)

    });

  }

  end() {

    pubInternal(this.requestChannel, {

      command: pb.Msg.Command.HTTP_RES_END

    });

  }

}

...

而之前 Response 的構(gòu)造方法中賦值的 requestChannel 作用就在于調(diào)用 res.write 和 res.end 時(shí), 能將 command 和 httpResWriteDate 傳遞給 Golang 中相應(yīng)的 handler, 所以這個(gè)值需要和 Golang 代碼中 Handler 中訂閱的 requestChan 相一致。

最后

到這里, 整個(gè)流程就已經(jīng)走通了, 接下來就是要在 ts 和 Golang 代碼中執(zhí)行模塊初始化

// main.go

...

func Init() {

  ...

  InitHTTP()

  ...

}

...

// main.ts

...

import { initHttp } from "./http";

(window as any)["denoMain"] = () => {

  ...

  initHttp()

  ...

}

...

然后在 deno.ts 中拋出 Request、Response 和 createHttpServer, 以供調(diào)用。

// deno.ts

...

export { createHttpServer, Response, Request } from "./http";

另外需要在 deno.d.ts 進(jìn)行類型定義, 這個(gè)不詳細(xì)說明了。

通過 make 進(jìn)行編譯即可, 在每次編譯之前最好都要 make clean 清理之前的編譯結(jié)果。

通過命令 ./deno helloServer.ts啟動(dòng)服務(wù)器, 就可以在瀏覽器訪問了。

Hello world!

到此,關(guān)于“如何讓deno支持HTTP服務(wù)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!


網(wǎng)頁名稱:如何讓deno支持HTTP服務(wù)
鏈接地址:http://weahome.cn/article/gjspso.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部