Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to make deno support HTTP Services

2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

这篇文章主要介绍"如何让deno支持HTTP服务",在日常操作中,相信很多人在如何让deno支持HTTP服务问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何让deno支持HTTP服务"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

现在的 deno 只支持很少的几个功能, 并不支持搭建 HTTP 服务, 如果想要用 deno 搭建 HTTP 服务要怎么办呢?

只能自己进行开发支持

代码如下:

// 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);

上面是我们期望创建服务器的代码, 接下来我们根据这段代码一点点实现

Request, Response, createHttpServer

上面说过, deno 现在并没有这些类和方法, 我们要构建这些对象和方法。

注: 这里并不是要写一个功能完善的模块, 有很多东西我都会省略掉

// 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;

}

在根目录创建 http.ts , 在其中进行定义。

Request 中有 method、path 两个属性, 简单起见, 浏览器请求中还有 body、header 等等其他实际中会用到的属性我都忽略了。

Response 中 requestChannel 是用于通过 deno 订阅/发布模式返回结果的, 后面能看到具体什么用。

HttpServer 中包括绑定的端口 port, 在构造函数中, 生成对 HttpServer 生成实例进行标识的 id, 及绑定对请求进行处理的函数 requestListener。

方法 createHttpServer 则是用 requestListener 创建 server 实例

server.listen

在有了 HttpServer 也绑定了 requestListenner 之后, 要监听端口

// 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 方法需要两个参数 channel 和 msgObj, 上面的代码就是将监听端口命令及所需的配置发布到 Golang 代码中 http 这个频道。

// 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 的定义文件)中对需要用到的 Command 以及 Msg 的属性进行定义, 需要注意的是, 属性值需要使用下划线命名, 在编译 deno 时会会根据这个文件生成对应的 msg.pb.d.ts、msg.pb.js 及 msg.pb.go 分别让 ts 及 Golang 代码使用, 这里对后续需要用到的定义都展示了, 后面不再赘述。

// 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()

}()

}

同样在根目录创建 http.go文件。

InitHTTP 中订阅 http channel, 在传入的 msg.command 为 Msg_HTTP_SERVER_LISTEN 时调用 httpListen 进行端口监听(还记得之前 msg.proto 中定义的枚举 Command 么, 在生成的 msg.proto.go 中会加上 Msg 前缀)。

httpListen 中用模块 net/http 新建了一个 httpServer, 对端口进行监听, 其中 Handler 后面再说。

wg 是个 sync.WaitGroup, 在 dispatch.go 中保证调度任务完成.

请求到来

在上面的代码中已经成功创建了 httpServer, 接下来浏览器发送 HTTP请求来到 http.go 中新建的 server 时, 需要将请求转交给 ts 代码中定义的 requestListener 进行响应。

// 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 {

...

initHttp()

...

}

...

然后在 deno.ts 中抛出 Request、Response 和 createHttpServer, 以供调用。

// deno.ts

...

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

另外需要在 deno.d.ts 进行类型定义, 这个不详细说明了。

通过 make 进行编译即可, 在每次编译之前最好都要 make clean 清理之前的编译结果。

通过命令 ./deno helloServer.ts启动服务器, 就可以在浏览器访问了。

Hello world!

到此,关于"如何让deno支持HTTP服务"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report