github 上已经有人搞了一个deno 的docker 镜像,是基于源码编译的,挺好的
所以结合官方的http server demo 使用docker 运行

环境准备

  • docker-compose 文件
 
version: "3"
services:
  app:
    image: maxmcd/deno:slim
    volumes:
    - "./app:/opt"
    command: deno /opt/app.ts
  file-server:
    image: maxmcd/deno:slim
    ports:
    - "4500:4500"
    volumes:
    - "./server:/opt/server"
    command: deno /opt/server/app.ts --allow-net
 
  • http server 内容
    http 模块的我修改为了使用http,就不用管下载的问题了
 
// This program serves files in the current directory over HTTP.
// TODO Stream responses instead of reading them into memory.
// TODO Add tests like these:
// https://github.com/indexzero/http-server/blob/master/test/http-server-test.js
import {
    listenAndServe,
    ServerRequest,
    setContentLength,
    Response
  } from "https://deno.land/x/net/http.ts";
  import { cwd, DenoError, ErrorKind, args, stat, readDir, open } from "deno";
  const dirViewerTemplate = `
  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Deno File Server</title>
    <style>
      td {
        padding: 0 1rem;
      }
      td.mode {
        font-family: Courier;
      }
    </style>
  </head>
  <body>
    <h1>Index of <%DIRNAME%></h1>
    <table>
      <tr><th>Mode</th><th>Size</th><th>Name</th></tr>
      <%CONTENTS%>
    </table>
  </body>
  </html>
  `;
  const serverArgs = args.slice();
  let CORSEnabled = false;
  // TODO: switch to flags if we later want to add more options
  for (let i = 0; i < serverArgs.length; i++) {
    if (serverArgs[i] === "--cors") {
      CORSEnabled = true;
      serverArgs.splice(i, 1);
      break;
    }
  }
  let currentDir = cwd();
  const target = serverArgs[1];
  if (target) {
    currentDir = `${currentDir}/${target}`;
  }
  const addr = `0.0.0.0:${serverArgs[2] || 4500}`;
  const encoder = new TextEncoder();
  function modeToString(isDir: boolean, maybeMode: number | null) {
    const modeMap = ["---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"];
    if (maybeMode === null) {
      return "(unknown mode)";
    }
    const mode = maybeMode!.toString(8);
    if (mode.length < 3) {
      return "(unknown mode)";
    }
    let output = "";
    mode
      .split("")
      .reverse()
      .slice(0, 3)
      .forEach(v => {
        output = modeMap[+v] + output;
      });
    output = `(${isDir ? "d" : "-"}${output})`;
    return output;
  }
  function fileLenToString(len: number) {
    const multipler = 1024;
    let base = 1;
    const suffix = ["B", "K", "M", "G", "T"];
    let suffixIndex = 0;
    while (base * multipler < len) {
      if (suffixIndex >= suffix.length - 1) {
        break;
      }
      base *= multipler;
      suffixIndex++;
    }
    return `${(len / base).toFixed(2)}${suffix[suffixIndex]}`;
  }
  function createDirEntryDisplay(
    name: string,
    path: string,
    size: number | null,
    mode: number | null,
    isDir: boolean
  ) {
    const sizeStr = size === null ? "" : "" + fileLenToString(size!);
    return `
    <tr><td class="mode">${modeToString(
      isDir,
      mode
    )}</td><td>${sizeStr}</td><td><a href="${path}">${name}${
      isDir ? "/" : ""
    }</a></td>
    </tr>
    `;
  }
  // TODO: simplify this after deno.stat and deno.readDir are fixed
  async function serveDir(req: ServerRequest, dirPath: string, dirName: string) {
    // dirname has no prefix
    const listEntry: string[] = [];
    const fileInfos = await readDir(dirPath);
    for (const info of fileInfos) {
      if (info.name === "index.html" && info.isFile()) {
        // in case index.html as dir...
        return await serveFile(req, info.path);
      }
      // Yuck!
      let mode = null;
      try {
        mode = (await stat(info.path)).mode;
      } catch (e) {}
      listEntry.push(
        createDirEntryDisplay(
          info.name,
          dirName + "/" + info.name,
          info.isFile() ? info.len : null,
          mode,
          info.isDirectory()
        )
      );
    }
    const page = new TextEncoder().encode(
      dirViewerTemplate
        .replace("<%DIRNAME%>", dirName + "/")
        .replace("<%CONTENTS%>", listEntry.join(""))
    );
    const headers = new Headers();
    headers.set("content-type", "text/html");
    const res = {
      status: 200,
      body: page,
      headers
    };
    setContentLength(res);
    return res;
  }
  async function serveFile(req: ServerRequest, filename: string) {
    const file = await open(filename);
    const fileInfo = await stat(filename);
    const headers = new Headers();
    headers.set("content-length", fileInfo.len.toString());
    const res = {
      status: 200,
      body: file,
      headers
    };
    return res;
  }
  async function serveFallback(req: ServerRequest, e: Error) {
    if (
      e instanceof DenoError &&
      (e as DenoError<any>).kind === ErrorKind.NotFound
    ) {
      return {
        status: 404,
        body: encoder.encode("Not found")
      };
    } else {
      return {
        status: 500,
        body: encoder.encode("Internal server error")
      };
    }
  }
  function serverLog(req: ServerRequest, res: Response) {
    const d = new Date().toISOString();
    const dateFmt = `[${d.slice(0, 10)} ${d.slice(11, 19)}]`;
    const s = `${dateFmt} "${req.method} ${req.url} ${req.proto}" ${res.status}`;
    console.log(s);
  }
  function setCORS(res: Response) {
    if (!res.headers) {
      res.headers = new Headers();
    }
    res.headers!.append("access-control-allow-origin", "*");
    res.headers!.append(
      "access-control-allow-headers",
      "Origin, X-Requested-With, Content-Type, Accept, Range"
    );
  }
  listenAndServe(addr, async req => {
    const fileName = req.url.replace(/\/$/, "");
    const filePath = currentDir + fileName;
    let response: Response;
    try {
      const fileInfo = await stat(filePath);
      if (fileInfo.isDirectory()) {
        // Bug with deno.stat: name and path not populated
        // Yuck!
        response = await serveDir(req, filePath, fileName);
      } else {
        response = await serveFile(req, filePath);
      }
    } catch (e) {
      response = await serveFallback(req, e);
    } finally {
      if (CORSEnabled) {
        setCORS(response);
      }
      serverLog(req, response);
      req.respond(response);
    }
  });
  console.log(`HTTP server listening on http://${addr}/`);
 
 

运行&&效果

  • 运行
docker-compose up -d
  • 效果

说明

deno 的安全控制上做的挺不错,因为使用了net ,所以需要在运行的时候指定 --allow-net

参考资料

https://github.com/rongfengliang/deno-docker-compose
https://deno.land/

deno学习四 docker 运行官方的一个http file server的更多相关文章

  1. docker 运行jenkins及vue项目与springboot项目(四.docker运行nginx)

    docker 运行jenkins及vue项目与springboot项目: 一.安装docker 二.docker运行jenkins为自动打包运行做准备 三.jenkins的使用及自动打包vue项目 四 ...

  2. Singer 学习五 docker 运行说明

    介绍过一个工具knots ,方便Singer 可视化开发的工具,但是默认这个工具包含的tap 以及target 比较少(可以自己扩展) 同时这个工具就是基于docker 运行的 docker 运行的几 ...

  3. ICE学习笔记一----运行官方的java版demo程序

    建议新手和我一样,从官网下载英文文档,开个有道词典,慢慢啃. 官方文档下载: http://download.csdn.net/detail/xiong_mao_1/6300631 程序代码就不说了, ...

  4. OpenGL学习——搭建OpenGL运行环境——生成一个空白视口——基于GLFW&GLEW

    最近学习OpenGL,读OpenGL宝典一头蒙,各种gl函数不知所云.逐决定先搭OpenGL运行环境,详细如下. 1.首先OpenGL是什么?是一个标准规范,是一个巨大的状态机,并无具体实现,大多数实 ...

  5. docker学习(四) - docker构建redis主从结构

    此文章假设你已经安装了docker,如果没有安装请查询本博客docker安装章节 容器网络 docker network ls  查看默认的网络 Docker安装后,默认会创建下面三种网络类型 在启动 ...

  6. JBPM学习(四):运行流程实例

    概念: ProcessInstance,流程实例:代表流程定义的一次执行.如:张三昨天按请假流程请了一次假.一个流程实例包含了全部执行阶段,当中最典型的属性就是跟踪当前节点的指针,例如以下图. Exe ...

  7. docker 运行jenkins及vue项目与springboot项目(三.jenkins的使用及自动打包vue项目)

    docker 运行jenkins及vue项目与springboot项目: 一.安装docker 二.docker运行jenkins为自动打包运行做准备 三.jenkins的使用及自动打包vue项目 四 ...

  8. benchmarkdotnet docker 运行

    使用docker 运行基准测试是一个不错的选择,可以减少我们环境搭建的时间,同时也可以加速ci/cd 环境准备 docker-compose 文件 version: "3" ser ...

  9. docker 运行jenkins及vue项目与springboot项目(一.安装docker)

    docker 运行jenkins及vue项目与springboot项目: 一.安装docker 二.docker运行jenkins为自动打包运行做准备 三.jenkins的使用及自动打包vue项目 四 ...

随机推荐

  1. java 2D图形绘制

    package jisuan; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; imp ...

  2. word-wrap与break-word属性的区别

    共同点 word-wrap:break-word与word-break:break-all都能把长单词强行断句 不同点 word-wrap:break-word会首先起一个新行来放置长单词,新的行还是 ...

  3. (C/C++学习笔记) 二十. 文件和流

    二十. 文件和流 ● 文件的概念 文件(file) 一. C/C++语言将文件作为字节序列(sequence of characters)来对待,但从编码角度,或说从对字节信息的解释来看,文件分为:文 ...

  4. PE文件 01 导入表

    0x01  导入表结构  数据目录表中的第二个成员标记了导入表的RVA和Size大小,由此可以定位到导入表: typedef struct _IMAGE_DATA_DIRECTORY { DWORD ...

  5. SUSE_LINUX 11 SP3 安装 IBM MQ 7.5

    0.环境介绍 mq7.5 suse linux 11 1. 上传安装包 上传安装包到 softWare/CI79IML.tar.gz 2. 安装证书 sh ./mqlicense.sh 输入 1 同意 ...

  6. day 31 udp 协议SOCK_DGRAM

    udp 服务端引用socket=类型,协议绑定地址 和 端口while 循环收到 data addr = 服务.recvfrom(1024)发送 服务.sendto(data,addr(ip 端口)) ...

  7. c++下基于windows socket的多线程服务器(基于TCP协议)

    之前用c++实现过基于windows socket的单线程TCP服务器(http://www.cnblogs.com/jzincnblogs/p/5170230.html),今天实现了一个多线程的版本 ...

  8. sql,取得当前系统时间,算时间区间

    mysql: SELECT * from (SELECT H_TEMPERATURE FROM WENSHIDU  WHERE TH_TIME >=date_sub(NOW(), interva ...

  9. Python基础2 字符编码和逻辑运算符

    编码 AscII码 :标准ASCII码是采用7位二进制码来编码的,最高为0,没有0000 0000,所以就是2**7-1=127个字符 , 当用1个字节(8位二进制码)来表示ASCII码时,就在最高位 ...

  10. 转:C++ 类的静态成员详细讲解

    在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用.所以在所有对象中都可以共享它.使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节 ...