Fen - 基於deno的簡單Typescript Web框架

deno 從誕生,到如今有本身的標準庫,以及一些第三方庫,讓我對deno在web的應用有了必定的興趣,html

我知道deno還沒有成熟,可是恰好最近心閒下來了,就找點事作作,做爲一個前端,我也期待經過這個機會了解更多的一些後臺的事情。前端

若是你能在看到文章以後,給我提出一些建議我將不勝感激~java

若是你也想一塊兒開發,我也很是歡迎~node

閱讀大約須要 4 - 5 分鐘git

基於deno v0.3.0,Github:https://github.com/fen-land/deno-fengithub

簡介

Fen 是一個使用Typescript基於deno的輕量級web框架,他經過Server主體來實現服務,經過Process以及Tool來賦予Server各類各樣的功能。web

Fen 僅僅經過上下問context來鏈接各個環節,雖然這樣的模式存在着上下文在修改過程當中難以保證穩定的問題,可是若是Process和Tool的開發遵照一些基本原則,仍是能基本維持context的穩定的。同時雖然 Fen 經過Process以及Tool來賦能,可是其自己仍是進行了必定的封裝以及進行了一些操做來讓使用更加便捷。typescript

由於其實沒有提出很新的想法,因此仍是使用了不少以前在java或者node中用過的後臺的用法,若是你們以爲有怎樣的新想法,也歡迎你們提issue。json

怎樣開始

首先,若是你不知道deno,快去看看吧: https://deno.land/瀏覽器

你須要安裝最新的deno:

curl -fsSL https://deno.land/x/install/install.sh | sh
複製代碼

而後,你須要寫你的第一個Fen的文件

// hello.ts
import { Server } from "https://raw.githubusercontent.com/fen-land/deno-fen/master/src/server.ts";

const s = new Server();

s.port = 8882;

s.start();
複製代碼

由於deno尚未相應成熟的包管理(也可能不會有)這裏引用文件還暫時是經過github來作一個託管,以後會完善一下,有更好的地址使用方式。

最後你須要運行這個文件

deno -A hello.ts
複製代碼

在瀏覽器中訪問:http://127.0.0.1:8882 你將會看到:

You have success build a server with fen on  0.0.0.0:1882

            Try set controller using setController method,
            Or try our route tool :)
複製代碼

這就是你的第一個 Fen 服務器。

Context

Context是Fen的核心概念,他起到了一個在生命週期裏面傳遞的做用,也是controller進行操做的手段。

結構以下:

{
 // ---- 這些變量都取自http派發都ServerRequest
  url,
  method,
  proto,
  headers,
  conn,
  reader,
  writer,
 // ---- 
  request,    
  path, // 不帶有參數的路徑
  params, // Map<string, string> url裏面獲得的參數 
  data: new Map<string, any>(),
  body: "",// respond 返回的body
  status: 200,// 狀態碼
  config: {
    disableRespond: false, // 禁用fen自帶的respond流程
    disableBodyEncode: false, // 禁止按照類型來encode body的流程
    disableContentType: false, // 禁止根據config來設置header
    mimeType: "text/plain", // 返回結果的mimeType
    charset: "utf-8" // 返回結果的Type
  },
  reqBody, // 嘗試解碼後的請求的body
  originBody, // 本來請求的body
  logger // tool 中帶有的Logger
};
複製代碼

經過使用context,你能夠經過簡單的賦值來決定響應:

s.setController(async ctx => {
  ctx.config.mimeType = "application/json";
  ctx.body = {
    now: "you",
    can: ["see"],
    me: 2
  };
});
複製代碼

Process

Process一般運行在controller前,爲context賦能,使其擁有特定的功能,Process經過addProcess方法來進行添加。

Session

Session是現有的惟一Process,他爲context加入了session這樣一個鍵,這樣就賦予了controller了web session的能力。

import {Server} from 'https://raw.githubusercontent.com/fen-land/deno-fen/raw/master/src/server.ts';
import Session from 'https://raw.githubusercontent.com/fen-land/deno-fen/raw/master/src/process/session.ts'

const session = new Session();

const s = new Server();

// session 加入的僅僅是session的process
s.addProcess(session.process);

s.port = 1882;

s.setController(
    async (ctx) => {
        // session 是一個 Map<string, any>()
        const {session} = ctx;
        let c = session.get('c') || 1;

        if(ctx.path === '/') {
            session.set('c',  c + 1);
        }

        ctx.body = `It\'s alive for path '/' ${c} times in this browser!`;
    }
);

s.start();
複製代碼

Tool

Fen要實現不少基本的功能相似於靜態文件,路由之類的,須要使用Tool,而且在Server中也使用了一些Tool。

Logger

Fen 本身有一個log系統,雖然是很簡陋的那種,可是能夠幫助開發時候獲得更多信息,你能夠在Server或者context中找到它。log是按照級別來提供的,你能夠在開發中使用logger.debug('debug')這樣的方式來產出log,低於設置level的log都不會產出。

'ALL': 全部log都輸出,
    'TRACE',
    'DEBUG',
    'INFO',
    'WARN',
    'ERROR',
    'FATAL',
    'OFF': 禁止全部log
複製代碼

你能夠經過 changeLevel來改變level:

logger.changeLevel('ALL');
複製代碼

Static

Static 爲 Server提供了靜態代理的功能,

import {Server} from 'https://raw.githubusercontent.com/fen-land/deno-fen/raw/master/src/server.ts';
import {staticProcess} from "https://raw.githubusercontent.com/fen-land/deno-fen/raw/master/src/tool/static.ts";

const s = new Server();

s.port = 1882;
// it will respond file from the path where deno run
s.setController(staticProcess({root: ''}));

s.start();
複製代碼

static提供了一些額外的option:

{
    root: root path of the file,
    maxAge: (s),
    allowHidden: allow access hidden file,
    index: access if no file name provide 'index.html',
    immutable: immutable in cache-control,
    pathRender: (path) => afterpath, if you want do sth. with path
};
複製代碼

Router

咱們爲Fen 也提供了路由Tool,他有很靈活的使用方法,你也能夠經過使用多個Router來進行開發,最後把他們merge到同一個上,下面展現了大部分可使用的路由方法的例子。

import { Server } from "https://raw.githubusercontent.com/fen-land/deno-fen/raw/master/src/server.ts";
import { Router } from "https://raw.githubusercontent.com/fen-land/deno-fen/raw/master/src/tool/router.ts";

const s = new Server();

s.port = 1882;

s.logger.changeLevel('ALL');

let mergeRouter = new Router('merge');

mergeRouter
  .get('/', async (ctx) => ctx.body = `${ctx.router.name} in ${ctx.router.route}`)
  .post('/', async (ctx) => ctx.body = `POST ${ctx.router.name} in ${ctx.router.route}`)
  .get('me', async (ctx) => ctx.body = `${ctx.router.name} in ${ctx.router.route}`);

let router = new Router();

router
  .get('/:id', async (ctx) => {
  ctx.body = `we have ${JSON.stringify(ctx.router.params)} in ${ctx.router.route}`
})
  .get('/:id/:name', async (ctx) => {
  ctx.body = `we have ${JSON.stringify(ctx.router.params)} in ${ctx.router.route}`
})
  .get('/hello/:name', async (ctx) => {
    ctx.body = `hello ${ctx.router.params.name} in ${ctx.router.route}`
  })
  .use({ '/use': {get: async (ctx) => ctx.body = `use in ${ctx.router.route}`}})
  .merge('/merge', mergeRouter);
;

s.setController(router.controller);

s.start();
複製代碼

Router 有如下的方法:

use(route: IRoute) // 一種區別於下面方法的直接批量添加路由的方式
    // IRoute 結構:
    // {[path]: {[method]: async function controller(cxt)}}
    merge(route: string, router:Router) // 你甚至能夠經過路徑前綴來合併Router們
    get
    post
    head
    put
    delete
    connect
    options
    trace
複製代碼

接下來

接下來Fen的開發計劃是:

  • 補充註釋和類型
  • 支持socket
  • 繼續開發Process和Tool
  • 添加自動測試
  • ……

(其實也存在我被畢業設計壓榨後到答辯前沒法完成的狀況)XD

相關文章
相關標籤/搜索