Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
|
fce36595f4 | |
|
e3fb4fcf41 | |
|
c5f8164281 | |
|
f7d0a106b7 | |
|
39b6d0ff75 | |
|
7e6c0f0123 | |
|
45e0ad2979 | |
|
7fb2479033 |
|
@ -22,6 +22,8 @@
|
||||||
> 在项目根目录中放置 `.httpserver`文件, 并配置好之后, 重启或重新加载窗口, 以启动服务。
|
> 在项目根目录中放置 `.httpserver`文件, 并配置好之后, 重启或重新加载窗口, 以启动服务。
|
||||||
|
|
||||||
|
|
||||||
|
## 插件通用配置
|
||||||
|
> 通用配置可以设置`domain`,`key`,`cert`3个字段, 可省的每个项目配置一次。通用配置优先级低于项目的配置。
|
||||||
|
|
||||||
## .httpserver 文件
|
## .httpserver 文件
|
||||||
> 使用`.httpserver`来配置web服务器信息, 该文件应为一个json格式的。
|
> 使用`.httpserver`来配置web服务器信息, 该文件应为一个json格式的。
|
||||||
|
@ -30,6 +32,11 @@
|
||||||
{
|
{
|
||||||
"enabled": true, // 这里配置为 true 才会启动web服务
|
"enabled": true, // 这里配置为 true 才会启动web服务
|
||||||
"port": 23333, // 【可选】 默认使用 23333 端口, 如果被使用了, 会向上查找可用端口
|
"port": 23333, // 【可选】 默认使用 23333 端口, 如果被使用了, 会向上查找可用端口
|
||||||
|
"https": true, // 【可选】 是否使用https
|
||||||
|
"http2": true, // 【可选】 是否使用http2, 等价于https, 用哪个都可以
|
||||||
|
"domain" "", // 【可选】有域名, 就会用域名打开页面, 没有就用IP
|
||||||
|
"key": "", // 【可选】域名证书的绝对路径(仅当开启https/2时需要)
|
||||||
|
"cert": "", // 【可选】域名证书的绝对路径(仅当开启https/2时需要)
|
||||||
"root": ".", // 【可选】 web服务的根目录, 默认为当前项目的根目录, 可填写相对项目根目录的路径。
|
"root": ".", // 【可选】 web服务的根目录, 默认为当前项目的根目录, 可填写相对项目根目录的路径。
|
||||||
"headers": { // 【可选】支持注入一些头信息, 方便特殊需要的调试
|
"headers": { // 【可选】支持注入一些头信息, 方便特殊需要的调试
|
||||||
"cache-control": "no-store" // 默认为 no-store
|
"cache-control": "no-store" // 默认为 no-store
|
||||||
|
|
122
index.js
122
index.js
|
@ -5,14 +5,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const vsc = require('vscode')
|
const vsc = require('vscode')
|
||||||
const { join } = require('path')
|
const { join, basename } = require('path')
|
||||||
const { parse } = require('url')
|
const { parse } = require('url')
|
||||||
const http = require('http')
|
const http = require('http')
|
||||||
|
const http2 = require('http2')
|
||||||
const fs = require('iofs')
|
const fs = require('iofs')
|
||||||
const { WebSocketServer } = require('ws')
|
const { WebSocketServer } = require('ws')
|
||||||
|
|
||||||
const std = vsc.window.createOutputChannel('http.server')
|
|
||||||
const decode = decodeURIComponent
|
const decode = decodeURIComponent
|
||||||
|
const statItem = vsc.window.createStatusBarItem(vsc.StatusBarAlignment.Left, 0)
|
||||||
|
|
||||||
const MIME_TYPES = {
|
const MIME_TYPES = {
|
||||||
html: 'text/html;charset=utf-8',
|
html: 'text/html;charset=utf-8',
|
||||||
|
@ -42,6 +43,7 @@ const MIME_TYPES = {
|
||||||
other: 'application/octet-stream'
|
other: 'application/octet-stream'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SERVER_OPTIONS = { allowHTTP1: true }
|
||||||
const COMMON_HEADERS = {
|
const COMMON_HEADERS = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
'Access-Control-Allow-Headers': '*',
|
'Access-Control-Allow-Headers': '*',
|
||||||
|
@ -49,6 +51,8 @@ const COMMON_HEADERS = {
|
||||||
'X-Powered-By': 'VS Code simple.http'
|
'X-Powered-By': 'VS Code simple.http'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CONFIG_FILE = '.httpserver'
|
||||||
|
|
||||||
MIME_TYPES.htm = MIME_TYPES.html
|
MIME_TYPES.htm = MIME_TYPES.html
|
||||||
MIME_TYPES.jpeg = MIME_TYPES.jpg
|
MIME_TYPES.jpeg = MIME_TYPES.jpg
|
||||||
MIME_TYPES.tif = MIME_TYPES.tiff
|
MIME_TYPES.tif = MIME_TYPES.tiff
|
||||||
|
@ -57,17 +61,15 @@ let root
|
||||||
let enabled = false
|
let enabled = false
|
||||||
let port = 23333
|
let port = 23333
|
||||||
let baseUrl = 'http://127.0.0.1:' + port
|
let baseUrl = 'http://127.0.0.1:' + port
|
||||||
|
let server
|
||||||
let ws = null
|
let ws = null
|
||||||
|
let domain
|
||||||
std.out = function (...args) {
|
let isHttps = false
|
||||||
std.appendLine('[simple.http]: ' + args.join(' '))
|
|
||||||
// console.log('[simple.http]: ' + args.join(' '))
|
|
||||||
}
|
|
||||||
|
|
||||||
const HMR_SCRIPT = `
|
const HMR_SCRIPT = `
|
||||||
<script>
|
<script>
|
||||||
!(function http_hmr(){
|
!(function http_hmr(){
|
||||||
var ws = new WebSocket(\`ws://\${location.host}/ws-http-hmr\`)
|
var ws = new WebSocket(\`\${location.protocol === 'https:' ? 'wss' : 'ws'}://\${location.host}/ws-http-hmr\`)
|
||||||
ws.addEventListener('open', function (r) {
|
ws.addEventListener('open', function (r) {
|
||||||
if(http_hmr.closed){
|
if(http_hmr.closed){
|
||||||
delete http_hmr.closed
|
delete http_hmr.closed
|
||||||
|
@ -115,13 +117,17 @@ class WebSocket {
|
||||||
|
|
||||||
function createServer() {
|
function createServer() {
|
||||||
if (port > 65535) {
|
if (port > 65535) {
|
||||||
std.out('端口超出有效范围0-65535, 当前为: ' + port)
|
|
||||||
enabled = false
|
enabled = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
std.out(`尝试使用${port}端口...`)
|
console.log(`尝试使用${port}端口...`)
|
||||||
const server = http
|
|
||||||
.createServer(function (req, res) {
|
server = (isHttps ? http2.createSecureServer : http.createServer)(
|
||||||
|
isHttps ? SERVER_OPTIONS : void 0
|
||||||
|
)
|
||||||
|
|
||||||
|
server
|
||||||
|
.on('request', function (req, res) {
|
||||||
let pathname = parse(req.url).pathname.slice(1)
|
let pathname = parse(req.url).pathname.slice(1)
|
||||||
let paths = pathname.split('/')
|
let paths = pathname.split('/')
|
||||||
|
|
||||||
|
@ -150,12 +156,12 @@ function createServer() {
|
||||||
.toString()
|
.toString()
|
||||||
.replace('</head>', HMR_SCRIPT + '</head>')
|
.replace('</head>', HMR_SCRIPT + '</head>')
|
||||||
|
|
||||||
res.setHeader('content-length', code.length)
|
res.setHeader('content-length', Buffer.byteLength(code))
|
||||||
} else {
|
} else {
|
||||||
res.setHeader('content-length', stat.size)
|
res.setHeader('content-length', stat.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
res.writeHead(200, 'OK')
|
res.writeHead(200, isHttps ? void 0 : 'OK')
|
||||||
|
|
||||||
if (ext === 'html') {
|
if (ext === 'html') {
|
||||||
res.end(code)
|
res.end(code)
|
||||||
|
@ -173,8 +179,24 @@ function createServer() {
|
||||||
|
|
||||||
res.setHeader('accept-ranges', 'bytes')
|
res.setHeader('accept-ranges', 'bytes')
|
||||||
res.setHeader('content-type', MIME_TYPES.html)
|
res.setHeader('content-type', MIME_TYPES.html)
|
||||||
res.setHeader('content-length', code.length)
|
res.setHeader('content-length', Buffer.byteLength(code))
|
||||||
res.writeHead(200, 'OK')
|
res.writeHead(200, isHttps ? void 0 : 'OK')
|
||||||
|
|
||||||
|
res.end(code)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let indexFile = join(root, 'index.html')
|
||||||
|
if (fs.isfile(indexFile)) {
|
||||||
|
code = fs
|
||||||
|
.cat(indexFile)
|
||||||
|
.toString()
|
||||||
|
.replace('</head>', HMR_SCRIPT + '</head>')
|
||||||
|
|
||||||
|
res.setHeader('accept-ranges', 'bytes')
|
||||||
|
res.setHeader('content-type', MIME_TYPES.html)
|
||||||
|
res.setHeader('content-length', Buffer.byteLength(code))
|
||||||
|
res.writeHead(200, isHttps ? void 0 : 'OK')
|
||||||
|
|
||||||
res.end(code)
|
res.end(code)
|
||||||
return
|
return
|
||||||
|
@ -182,32 +204,46 @@ function createServer() {
|
||||||
}
|
}
|
||||||
res.setHeader('content-length', 0)
|
res.setHeader('content-length', 0)
|
||||||
res.setHeader('x-url', file)
|
res.setHeader('x-url', file)
|
||||||
res.writeHead(404, 'Not Found')
|
res.writeHead(404, isHttps ? void 0 : 'Not Found')
|
||||||
res.end('')
|
res.end(null)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.listen(port)
|
|
||||||
.on('error', err => {
|
.on('error', err => {
|
||||||
std.out(`${port}端口被占用~~~`)
|
console.log(`${port}端口被占用~~~`)
|
||||||
port++
|
port++
|
||||||
createServer()
|
createServer()
|
||||||
})
|
})
|
||||||
|
.on('listening', _ => {
|
||||||
|
baseUrl = `http${isHttps ? 's' : ''}://${domain || '127.0.0.1'}:${port}`
|
||||||
|
ws = new WebSocket(server)
|
||||||
|
statItem.text = `http.server (🟢)`
|
||||||
|
statItem.show()
|
||||||
|
})
|
||||||
|
.listen(port)
|
||||||
|
|
||||||
server.on('listening', _ => {
|
return server
|
||||||
baseUrl = 'http://127.0.0.1:' + port
|
|
||||||
ws = new WebSocket(server)
|
|
||||||
std.out('启动成功, 请访问', baseUrl)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function __init__() {
|
function __init__() {
|
||||||
let folders = vsc.workspace.workspaceFolders
|
let folders = vsc.workspace.workspaceFolders
|
||||||
|
let commonConfig = vsc.workspace.getConfiguration('HttpServer')
|
||||||
|
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
statItem.hide()
|
||||||
|
|
||||||
if (folders && folders.length) {
|
if (folders && folders.length) {
|
||||||
root = folders[0].uri.fsPath
|
root = folders[0].uri.fsPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server) {
|
||||||
|
server.close()
|
||||||
|
server.closeAllConnections()
|
||||||
|
server = null
|
||||||
|
}
|
||||||
|
|
||||||
if (root) {
|
if (root) {
|
||||||
let file = join(root, '.httpserver')
|
let file = join(root, CONFIG_FILE)
|
||||||
//
|
//
|
||||||
if (fs.isfile(file)) {
|
if (fs.isfile(file)) {
|
||||||
let conf = JSON.parse(fs.cat(file).toString())
|
let conf = JSON.parse(fs.cat(file).toString())
|
||||||
|
@ -215,6 +251,7 @@ function __init__() {
|
||||||
if (conf.root) {
|
if (conf.root) {
|
||||||
root = join(root, conf.root)
|
root = join(root, conf.root)
|
||||||
}
|
}
|
||||||
|
isHttps = conf.https || conf.http2
|
||||||
|
|
||||||
if (conf.headers) {
|
if (conf.headers) {
|
||||||
for (let k in conf.headers) {
|
for (let k in conf.headers) {
|
||||||
|
@ -226,27 +263,47 @@ function __init__() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isHttps) {
|
||||||
|
let key = conf.key || commonConfig.key
|
||||||
|
let cert = conf.cert || commonConfig.cert
|
||||||
|
|
||||||
|
if (key) {
|
||||||
|
SERVER_OPTIONS.key = fs.cat(key)
|
||||||
|
}
|
||||||
|
if (cert) {
|
||||||
|
SERVER_OPTIONS.cert = fs.cat(cert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
domain = conf.domain || commonConfig.domain
|
||||||
|
|
||||||
if (conf.enabled) {
|
if (conf.enabled) {
|
||||||
enabled = true
|
enabled = true
|
||||||
port = conf.port || 23333
|
port = conf.port || 23333
|
||||||
|
|
||||||
createServer()
|
createServer()
|
||||||
} else {
|
} else {
|
||||||
std.out('发现配置文件, 但服务为 关闭状态')
|
statItem.text = `http.server (🔴)`
|
||||||
|
statItem.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deactivate() {}
|
export function deactivate() {}
|
||||||
|
|
||||||
exports.activate = function (ctx) {
|
export function activate(ctx) {
|
||||||
__init__()
|
__init__()
|
||||||
|
|
||||||
|
vsc.workspace.onDidChangeConfiguration(__init__)
|
||||||
|
|
||||||
vsc.workspace.onDidSaveTextDocument(doc => {
|
vsc.workspace.onDidSaveTextDocument(doc => {
|
||||||
if (enabled) {
|
let file = doc.fileName
|
||||||
let file = doc.fileName
|
if (file?.startsWith(root)) {
|
||||||
if (file.startsWith(root)) {
|
if (basename(file) === CONFIG_FILE) {
|
||||||
|
return __init__()
|
||||||
|
}
|
||||||
|
if (enabled) {
|
||||||
ws.send()
|
ws.send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,4 +321,3 @@ exports.activate = function (ctx) {
|
||||||
})
|
})
|
||||||
ctx.subscriptions.push(cmd)
|
ctx.subscriptions.push(cmd)
|
||||||
}
|
}
|
||||||
exports.deactivate = deactivate
|
|
||||||
|
|
29
package.json
29
package.json
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "simple-http",
|
"name": "simple-http",
|
||||||
"displayName": "simple http",
|
"displayName": "simple http.server",
|
||||||
"description": "🔥 简单的http服务器, 方便临时调试html",
|
"description": "🔥 简单的http服务器, 方便临时调试html",
|
||||||
"version": "1.5.0",
|
"version": "1.7.0",
|
||||||
"publisher": "yutent",
|
"publisher": "yutent",
|
||||||
"author": "Yutent [@yutent]",
|
"author": "Yutent [@yutent]",
|
||||||
"icon": "logo.png",
|
"icon": "logo.png",
|
||||||
|
@ -31,11 +31,32 @@
|
||||||
"title": "在浏览器中打开"
|
"title": "在浏览器中打开"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "HttpServer 通用配置",
|
||||||
|
"properties": {
|
||||||
|
"HttpServer.domain": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "默认域名(需要手动绑hosts或DNS解析)"
|
||||||
|
},
|
||||||
|
"HttpServer.key": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "域名的证书的绝对路径"
|
||||||
|
},
|
||||||
|
"HttpServer.cert": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "域名的证书的绝对路径"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/yutent/http.server.git"
|
"url": "https://git.wkit.fun/yutent/http.server.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"http.server",
|
"http.server",
|
||||||
|
@ -44,7 +65,7 @@
|
||||||
"yutent"
|
"yutent"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bundle": "esbuild index.js --bundle --outfile=out.js --external:vscode --format=cjs --platform=node",
|
"bundle": "esbuild index.js --bundle --outfile=out.js --external:vscode --format=cjs --target=es2020 --platform=node",
|
||||||
"start": "npm run bundle -- --watch",
|
"start": "npm run bundle -- --watch",
|
||||||
"pack": "npm run bundle -- --minify"
|
"pack": "npm run bundle -- --minify"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
{
|
{
|
||||||
"enabled": true
|
"enabled": true,
|
||||||
}
|
"https": false,
|
||||||
|
"port": 9090
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
sdsdsdsdsssdsdsd
|
sdsdsdsdsssdsdsd
|
||||||
dsdsd
|
ssssdddfdfd
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue