更新记录

1.1.0(2025-07-06)

修复bug

1.0.0(2025-07-06)

1.0新发布


平台兼容性

uni-app x

Chrome Safari Android iOS 鸿蒙 微信小程序
- - 5.0 × × ×

介绍

本插件仅适用于安卓,可以实现部署一个web页面,并可添加代理路径,或添加自定义处理路径,支持路径参数,如"/test/{page}/user/{id}/home"。 下方示例均为uts语言调用,js调用时去除类型声明。

开始

通过调用createServer(port:number,host:string="0.0.0.0"):IWebFileServer方法创建一个服务器实例

示例:

const server:IWebFileServer=createServer(5123,'0.0.0.0')

返回值:

IWebFileServer 接口定义了一组方法,用于操作和管理 Web 服务器,支持添加资源处理、设置跨域访问、修改静态文件路径等功能。该接口实现了通过 HTTP 服务器提供静态文件服务和处理动态请求的能力。

IWebFileServer接口方法及说明

1. start()

启动服务器。

返回值:

boolean - 如果服务器启动成功,返回 true,否则返回 false

示例:

let server:IWebFileServer=createServer(5123,'0.0.0.0')
if (server.start()) {
    console.log('服务器启动成功');
} else {
    console.log('服务器启动失败');
}

2. getHostname()

获取服务器监听的主机名。

返回值:

string - 返回监听的主机名。

示例:

const hostname = server.getHostname();
console.log('服务器主机名:', hostname);

3. getListeningPort()

获取服务器监听的端口号。

返回值:

number - 返回监听的端口号。

示例:

const port = server.getListeningPort();
console.log('服务器监听端口:', port);

4. isAlive()

检查服务器是否处于运行状态。

返回值:

boolean - 如果服务器运行中,返回 true,否则返回 false

示例:

if (server.isAlive()) {
    console.log('服务器正在运行');
} else {
    console.log('服务器未运行');
}

5. setCors(v: boolean)

设置服务器是否允许跨域请求。

参数:

  • v (boolean):如果为 true,服务器将允许跨域访问。

示例:

server.setCors(true);  // 允许跨域请求

6. stop()

关闭服务器。

示例:

server.stop();  // 停止服务器

7. addResourceHandler(method: string, uri: string, handler: IResourceHandler)

为指定的 URI 添加同步资源处理器,当定义的资源路径与代理路径重叠时将抛出异常。

参数:

  • method (string):HTTP 请求方法,如 "GET""POST" 等。
  • uri (string):URI 路径,可以包含路径参数(如 "/api/{test}/user/{id}")。
  • handler (session:ISession,response:IResponse)=>void:同步资源处理器回调函数,接收 sessionresponse 两个参数。
  • ISession,IResponse定义查看下方

示例:

server.addResourceHandler(MethodType.GET,"/test/{page}/user/{id}/home",
    function(session:ISession,response:IResponse):void{
        //获取路径参数page
        console.log(session.pathVariable["page"])
        //获取路径参数id
        console.log(session.pathVariable["id"])
        //获取请求体
        console.log(session.body)
        //获取请求体解析后的json对象(若content-type为text/json)
        console.log(session.json)
        //获取查询参数
        console.log(session.params)
        //获取请求头
        console.log(session.headers)
        //获取请求cookie
        console.log(session.cookie)
        //设置返回文件
        // response.body_file="/storage/emulated/0/Android/data/包名/apps/__UNI__xxxxx/www/static/assets/nanohttpd/default-mimetypes.properties"
        //设置返回json对象,将自动解析为json字符串
        // response.body_json={a:12,v:{b:"123"}}
        //设置返回字符串
        response.body_text="测试一下"
        //设置返回头
        response.header={"head1":"aaabbb","head2":3242,"head3":{name:"aadd"}}
    })

8. addAsyncResourceHandler(method: string, uri: string, handler: IAsyncResourceHandler)

为指定的 URI 添加异步资源处理器,支持异步操作如网络请求、文件读取等,当定义的资源路径与代理路径重叠时将抛出异常。

参数:

  • method (string):HTTP 请求方法,如 "GET""POST" 等,或使用 MethodType.REQUEST 接收所有请求方法。
  • uri (string):URI 路径,可以包含路径参数(如 "/api/{test}/user/{id}")。
  • handler (session:ISession,response:IResponse)=>Promise:异步资源处理器回调函数,返回 Promise。

特性说明:

  • 异步支持:支持在处理器中执行异步操作,如网络请求、数据库查询等
  • 错误处理:自动捕获异步操作中的错误并返回500状态码
  • 性能优化:使用轮询机制等待异步操作完成,避免阻塞服务器

示例:

// 基本异步处理器
server.addAsyncResourceHandler(MethodType.GET, "/api/data/{id}", 
    async (session: ISession, response: IResponse): Promise<void> => {
        try {
            const id = session.pathVariable["id"]
            console.log(`处理异步请求,ID: ${id}`)

            // 模拟异步数据获取
            const data = await fetchDataFromAPI(id)

            response.body_json = {
                success: true,
                data: data,
                timestamp: Date.now()
            }
            response.status = Status.OK
            response.header = {
                "Content-Type": "application/json",
                "Access-Control-Allow-Origin": "*"
            }
        } catch (error) {
            console.error(`异步处理失败: ${error}`)
            response.body_json = {
                success: false,
                error: error.toString()
            }
            response.status = Status.INTERNAL_ERROR
        }
    })

// M3U8代理处理器示例
server.addAsyncResourceHandler(MethodType.REQUEST, "/m3u8-proxy", 
    async (session: ISession, response: IResponse): Promise<void> => {
        const urlParamList = session.params["url"]
        const urlParam = urlParamList != null && urlParamList.size > 0 ? urlParamList[0] : null

        if (urlParam == null || urlParam == '') {
            response.body_text = 'Missing url parameter'
            response.status = Status.BAD_REQUEST
            return
        }

        try {
            const decodedUrl = decodeURIComponent(urlParam)
            const result = await processM3U8Content(decodedUrl)

            if (result.success) {
                response.body_text = result.content ?? ''
                response.header = {
                    'Content-Type': 'application/vnd.apple.mpegurl',
                    'Access-Control-Allow-Origin': '*',
                    'Cache-Control': 'no-cache'
                }
                response.status = Status.OK
            } else {
                response.body_text = result.error ?? 'M3U8处理失败'
                response.status = Status.INTERNAL_ERROR
            }
        } catch (error) {
            response.body_text = `M3U8处理异常: ${error}`
            response.status = Status.INTERNAL_ERROR
        }
    })

// 模拟异步数据获取函数
async function fetchDataFromAPI(id: string): Promise<any> {
    // 模拟网络延迟
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve({ id: id, name: "示例数据", value: Math.random() })
        }, 100)
    })
}

// 模拟M3U8内容处理函数
async function processM3U8Content(url: string): Promise<{success: boolean, content?: string, error?: string}> {
    // 实际实现中这里会进行网络请求和内容处理
    return { success: true, content: "#EXTM3U\n#EXT-X-VERSION:3\n..." }
}

ISession,IResponse,IResourceHandler,IAsyncResourceHandler定义

export type ISession={
    /**请求的路径地址*/
    uri:string
    /**
     * 获取请求查询参数,上传的表单参数也会存储于此,同名参数值存入同一列表
     */
    params:MutableMap<string,MutableList<String>>
    /**请求的查询参数原字符串*/
    queryParameterString:string|null
    /**请求头*/
    headers:MutableMap<string,string>
    /**请求的方法*/
    method:string
    /**远程主机名*/
    remoteHostName:string
    /**远程ip地址*/
    remoteIpAddress:string
    /**当为POST方法时,此处获取body*/
    body:string|null
    /**当为PUT方法时,此处为存储的文件的临时位置*/
    tempFilePath:string|null
    /**当为POST方法,且content-type为"application/json",且body不为null时,会自动解析body并存于body字段*/
    json:UTSJSONObject|null
    /** 获取cookie,Map类型,以cookie的name为键 */
    cookie:MutableMap<string,string>
    /**请求的路径参数,为Map类型,值始终为string类型,若需其它类型需自行转换*/
    pathVariable:MutableMap<string,string>
}
export type IResponse={
    /**状态码,默认为OK(200),可取值参照nanohttpd中Status枚举值*/
    status:number
    /** 当该值不为null时,将读取该路径下文件并返回,路径应为文件的绝对路径,此时body_text、body_json字段将被无视,注意,当文件位于公共存储空间时需申请文件读取权限 */
    body_file:string|null
    /** 当该值不为null时,且body_file为null时,将该值转为json字符串返回,此时body_text字段将被无视 */
    body_json:any|null
    /** 当该值不为null时,且body_file、body_json为null时,将该值作为响应体返回*/
    body_text:string|null
    /**响应的content-type值,为null时自动设置,默认值为null*/
    mimetype:string|null
    /** 响应头,默认值为null*/
    header:UTSJSONObject|null
}

/**
 * 同步资源处理器接口
 */
export type IResourceHandler = (session: ISession, response: IResponse) => void

/**
 * 异步资源处理器接口
 * 支持异步操作,如网络请求、文件读取等
 */
export type IAsyncResourceHandler = (session: ISession, response: IResponse) => Promise<void>

8. addProxyPath(uri: string, targetHost: string)

添加一个代理路径,将请求转发到目标服务器,当定义的代理路径与资源路径重叠时将覆盖资源路径。

参数:

  • uri (string):本地服务器的 URI 路径。
  • targetHost (string):目标服务器的地址。

示例:

//对于该服务器的请求如"/proxy/api/user/get/info"将自动请求"www.proxy.example:12345/user/get/info"并返回响应
server.addProxyPath('/proxy/api', 'http://www.example.com');

9. addVideoStreamProxy(uri: string, targetHost: string, options?: IVideoStreamProxyOptions)

添加视频流代理转发路径,专门针对视频流进行优化,支持断点续传、流式传输等特性。

参数:

  • uri (string):本地服务器的 URI 路径。
  • targetHost (string):目标视频流服务器的地址。
  • options (IVideoStreamProxyOptions, 可选):视频流代理配置选项。

IVideoStreamProxyOptions 配置选项:

  • enableRangeRequest (boolean, 默认: true):是否启用Range请求支持(断点续传)
  • bufferSize (number, 默认: 8192):缓冲区大小(字节)
  • connectionTimeout (number, 默认: 30000):连接超时时间(毫秒)
  • readTimeout (number, 默认: 60000):读取超时时间(毫秒)
  • enableStreaming (boolean, 默认: true):是否启用流式传输
  • supportedMimeTypes (string[], 默认: ["video/mp4", "video/webm", "video/ogg", "application/vnd.apple.mpegurl", "application/dash+xml"]):支持的视频格式MIME类型列表

示例:

// 基本用法
server.addVideoStreamProxy('/video', 'http://video.example.com:8080');

// 高级配置
const videoOptions: IVideoStreamProxyOptions = {
    enableRangeRequest: true,
    bufferSize: 16384,
    connectionTimeout: 30000,
    readTimeout: 120000,
    enableStreaming: true,
    supportedMimeTypes: ['video/mp4', 'application/vnd.apple.mpegurl']
};
server.addVideoStreamProxy('/stream', 'http://streaming.server.com', videoOptions);

// 访问示例:
// http://localhost:8080/video/movie.mp4 -> http://video.example.com:8080/movie.mp4
// http://localhost:8080/stream/live.m3u8 -> http://streaming.server.com/live.m3u8

特性说明:

  • 断点续传:支持HTTP Range请求,实现视频的断点续传功能
  • 流式传输:支持大文件的流式传输,减少内存占用
  • 多格式支持:自动识别MP4、WebM、OGG、HLS(m3u8)、DASH(mpd)等视频格式
  • 智能缓存:保留重要的缓存相关头部信息
  • 错误处理:完善的错误处理和日志记录

10. updateStaticFilePathType(staticFilePathType: number)

更新静态文件的路径类型,路径类型默认为Assets,可选值:Assets,Static,Public。 分别表示应用内部存储空间,应用外部存储空间,公共存储空间。

参数:

  • staticFilePathType (number):路径类型,可以是 StaticPathType.AssetsStaticPathType.StaticStaticPathType.Public

示例:

server.updateStaticFilePathType(StaticPathType.Static);

10. updateStaticFilePath(path: string)

更新静态资源文件的路径,当前路径类型将影响更新路径的过程。

参数:

  • path (string):新的静态文件路径。

示例:

server.updateStaticFilePath('assets/static');

11. getStaticFilePath()

获取当前静态资源文件的路径。

返回值:

string - 当前静态文件路径,需结合路径类型判断实际文件路径。

示例:

const staticFilePath = server.getStaticFilePath();
console.log('静态文件路径:', staticFilePath);

12. getStaticFilePathType()

获取当前静态文件路径的类型。

返回值:

number - 静态文件路径类型,值可以是 0(Assets)、1(Static)、2(Public)。

示例:

const staticFilePathType = server.getStaticFilePathType();
console.log('静态文件路径类型:', staticFilePathType);

13. updateStaticMimeFilePath(path: string)

更新 Mime 类型配置文件的位置。

参数:

  • path (string):Mime 类型文件的路径,应该是父目录路径。

示例:

server.updateStaticMimeFilePath('/static/assets/nanohttpd');

导出方法

setLogLevel(level:number)

设置服务器自带日志的输出等级

参数:

  • level (number):服务器内置日志的输出等级

导出类

可用其中的静态属性,方便赋值,插件更新时也可提供更好的兼容性 包含:StaticPathType,MethodType,LogLevel,Status

完整uts语言调用演示如下,js调用时需将类型声明去除:

<template>
    <view style="height: 100%;">
        <view style="height: 50%;">
            <web-view ref="web" src="http://127.0.0.1:5123"></web-view>
        </view>
        <scroll-view>
            <button @click="refresh_page" class="bt">刷新页面</button>
            <button @click="open_server" class="bt">开启服务器</button>
            <button @click="is_alive" class="bt">是否运行:{{alive}}</button>
            <button @click="get_port" class="bt">获取监听端口:{{port}}</button>
            <button @click="get_host" class="bt">获取监听地址:{{host}}</button>
            <button @click="stop_server" class="bt">关闭服务器</button>
        </scroll-view>
    </view>
</template>

<script>
    import { createServer,IWebFileServer,StaticPathType,MethodType,IResourceHandler,IAsyncResourceHandler,ISession,IResponse,setLogLevel,LogLevel,Status } from "@/uni_modules/xzhao-uts-LocalHttpServer"
    let server:IWebFileServer=createServer(5123,'0.0.0.0')
    export default {
        data() {
            return {
                server:null,
                alive:false,
                port:-1,
                host:''
            }
        },
        onLoad() {
            console.log(server)
            //设置日志等级
            setLogLevel(LogLevel.ALL)
            //更新静态资源路径类型
            server.updateStaticFilePathTypeWithPath(StaticPathType.Static,"assets/static")
            // server.updateStaticFilePath("public")
            console.log("静态资源路径为:",server.getStaticFilePath())
            console.log("静态资源路径类型为:",server.getStaticFilePathType())
            //更新mimetype文件路径
            server.updateStaticMimeFilePath("/storage/emulated/0/Android/data/包名/__UNI__xxxxxx/www/static/assets/mime/")
            //设置允许跨域访问本服务器
            server.setCors(true)
            //添加同步路径处理
            server.addResourceHandler(MethodType.GET,"/test/{page}/user/{id}/home",
                function(session:ISession,response:IResponse):void{
                    console.log(session.pathVariable["page"])
                    console.log(session.pathVariable["id"])
                    console.log(session.body)
                    console.log(session.json)
                    console.log(session.params)
                    console.log(session.headers)
                    console.log(session.cookie)
                    // response.body_file="/storage/emulated/0/Android/data/包名/apps/__UNI__xxxxx/www/static/assets/nanohttpd/default-mimetypes.properties"
                    // response.body_json={a:12,v:{b:"123"}}
                    response.body_text="测试一下"
                    response.header={"head1":"aaabbb","head2":3242,"head3":{name:"aadd"}}
                    response.status=Status.OK
                })

            //添加异步API处理器
            server.addAsyncResourceHandler(MethodType.GET, "/api/user/{id}", 
                async (session: ISession, response: IResponse): Promise<void> => {
                    try {
                        const userId = session.pathVariable["id"]
                        console.log(`获取用户信息,ID: ${userId}`)

                        // 模拟异步数据库查询
                        const userData = await this.fetchUserData(userId)

                        response.body_json = {
                            success: true,
                            user: userData
                        }
                        response.status = Status.OK
                        response.header = {
                            "Content-Type": "application/json"
                        }
                    } catch (error) {
                        console.error(`获取用户数据失败: ${error}`)
                        response.body_json = {
                            success: false,
                            error: "用户数据获取失败"
                        }
                        response.status = Status.INTERNAL_ERROR
                    }
                })

            //添加M3U8代理处理器
            server.addAsyncResourceHandler(MethodType.REQUEST, "/m3u8-proxy", 
                async (session: ISession, response: IResponse): Promise<void> => {
                    const urlParamList = session.params["url"]
                    const urlParam = urlParamList != null && urlParamList.size > 0 ? urlParamList[0] : null

                    if (urlParam == null || urlParam == '') {
                        response.body_text = 'Missing url parameter'
                        response.status = Status.BAD_REQUEST
                        return
                    }

                    try {
                        const decodedUrl = decodeURIComponent(urlParam)
                        const m3u8Content = await this.fetchM3U8Content(decodedUrl)

                        response.body_text = m3u8Content
                        response.header = {
                            'Content-Type': 'application/vnd.apple.mpegurl',
                            'Access-Control-Allow-Origin': '*'
                        }
                        response.status = Status.OK
                    } catch (error) {
                        response.body_text = `M3U8代理失败: ${error}`
                        response.status = Status.INTERNAL_ERROR
                    }
                })

            //添加代理路径
            server.addProxyPath("/proxy/test/","http://127.0.0.1:12345")
            //添加视频流代理
            server.addVideoStreamProxy("/video", "http://video.example.com:8080", {
                enableRangeRequest: true,
                bufferSize: 16384,
                enableStreaming: true,
                supportedMimeTypes: ["video/mp4", "application/vnd.apple.mpegurl"]
            })
            //测试代理路径
            let targetServer=createServer(12345)
            targetServer.addResourceHandler(MethodType.REQUEST,"/be/proxy",
                function(session:ISession,response:IResponse):void{
                    console.log("接收到请求")
                    response.body_json={"目标代理服务器":"返回结果","dwad":123123,"89879":["wadad"]}
                })
            targetServer.start()
        },
        methods: {
            // 模拟异步数据获取函数
            async fetchUserData(userId: string): Promise<any> {
                // 模拟网络延迟
                return new Promise((resolve) => {
                    setTimeout(() => {
                        resolve({
                            id: userId,
                            name: "用户" + userId,
                            email: `user${userId}@example.com`
                        })
                    }, 200)
                })
            },

            async fetchM3U8Content(url: string): Promise<string> {
                // 实际实现中这里会进行网络请求
                return "#EXTM3U\n#EXT-X-VERSION:3\n#EXTINF:10.0,\nsegment1.ts\n#EXT-X-ENDLIST"
            },

            refresh_page(){
                let w=this.$refs["web"] as UniWebViewElement
                w.reload()
            },
            open_server(){
                server.start()
            },
            get_host(){
                this.host=server.getHostname()
            },
            get_port(){
                this.port=server.getListeningPort()
            },
            is_alive(){
                this.alive=server.isAlive()
            },
            stop_server(){
                server.stop()
            }
        }
    }
</script>

<style>
    .logo {
        height: 100px;
        width: 100px;
        margin: 100px auto 25px auto;
    }

    .bt {
        font-size: 18px;
        color: #8f8f94;
        text-align: center;
    }
</style>

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问