import { type Server as HttpServer, type IncomingHttpHeaders, type IncomingMessage, type ServerResponse } from 'node:http'; import { type Http2SecureServer, type ServerHttp2Stream, type IncomingHttpHeaders as IncomingHttp2Headers, type OutgoingHttpHeaders as OutgoingHttp2Headers } from 'node:http2'; import type { Duplex, Readable } from 'node:stream'; import type { QuicStream } from 'node:quic'; import type { Socket } from 'node:net'; import type { WebSocketServer } from 'ws'; import { Remote, type RequestOptions, type RawResponse, type MessageHandler } from './net.ts'; export declare class Server { /** proxy 时需要丢弃的 resposne headers */ static drop_response_headers: Set; name: string; print: { info: boolean; logs: boolean; errors: boolean; }; /** sea 下最后修改时间,用于 http 资源缓存 */ last_modified_str?: string; static js_exts: Set; static logger_ignore_fexts: Set; static empty_body_statuses: Set; static empty_body_methods: Set; static windows_platform_versions: { legacy: { 0.1: string; 0.2: string; 0.3: string; }; /** platform_version (1 ~ 8) - 1 作为索引下标 */ win10: string[]; }; static ignore_error_codes: Set; /** 启用 http server */ http: boolean; /** 启用 http2 server */ http2: boolean; http_port: number; http2_port: number; /** http2 server 证书文件夹路径,设置后才会启用 http2 server */ fpd_certs?: string; default_hostnames?: string[]; http_server: HttpServer; http2_server?: Http2SecureServer; websocket_server?: WebSocketServer; /** 设置后会启用 websocket rpc */ funcs?: Record; /** 输出日志时包含日期 */ log_date: boolean; /** 启用后增加 stdio 订阅相关的 remote.funcs */ stdio_subscribable?: boolean; stdio_subscribers: StdioSubscriber[]; /** 原始 process.stdout.write 函数 bind 后的备份 */ stdout_write: Function; stderr_write: Function; constructor({ name, print, http, http2, http_port, http2_port, fpd_certs, default_hostnames, funcs, stdio_subscribable, log_date }: { name: string; print?: boolean | { info?: boolean; logs?: boolean; errors: boolean; }; http?: boolean; http2?: boolean; http_port?: number; http2_port?: number; fpd_certs?: string; default_hostnames?: string[]; funcs?: Remote['funcs']; stdio_subscribable?: true; log_date?: boolean; }); /** start http server and listen */ start(): Promise; try_write_stdio_subscribers(chunk: string | Uint8Array): void; stop(): void; /** 可被子类重写定义错误处理逻辑 */ on_error(error: Error & { code?: string; }, ctx?: Context): void; on_upgrade(request: IncomingMessage, socket: Duplex, head: Buffer): void; on_request(v: 1 | 2 | 3, stream: QuicStream | ServerHttp2Stream, headers: RequestHeaders, h2body?: boolean, req?: IncomingMessage, res?: ServerResponse): Promise; /** 可被子类重写,有了 http_server 和 http2_server 后在 listen 之前做一些自定义处理逻辑 */ init_server(): Promise; /** 被子类重写以自定义处理逻辑,声明返回 Promise 而非 Promise,方便短路返回表达式 */ router(ctx: Context): Promise; logger({ method: _method, version, https, h1, queries, body, path, _path, host, ip, headers, }: Request): void; /** model? platform platform_version / mobile browser */ get_client_info(headers: IncomingHttpHeaders | IncomingHttp2Headers): string; get_client_platform_and_version(platform: string, version: string): any; /** 转发请求到其他 http 服务,实现网关的功能,返回 true 返回 true 是为了方便 return this.request(...) 这样的剪枝写法 - ctx - path_url: 只含 host, path, 不含 queries 的 url, 如 http://localhost:8080/api/get-user 实际请求时会自动带上 ctx 中的 queries - options?: ServerRequestOptions - headers?: 修改 (添加、覆盖、null 值时删除) 请求的 http headers, Record - queries?: 修改 (添加、覆盖、null 值时删除) 请求的 http queries, Record - redirect?: `manual` 重定向处理策略,默认按原样返回给客户端 - timeout?: `1000 * 5` 请求超时时间,可以传入 0 禁用超时 - throw_error?: `false` 在遇到 request 请求错误时直接 throw 出来,而不是自动设置到 response - print_error?: `true` 是否打印代理 http 错误 */ request(ctx: Context, path_url: string | URL, { headers: headers_, redirect, queries, timeout, throw_error, proxy, print_error }?: ServerRequestOptions): Promise; static filter_response_headers(headers: RawResponse['headers']): IncomingHttp2Headers; /** 提供静态文件,返回是否成功 - ctx - fp: 文件路径 - 有 fpd_root 时为相对路径或以 fpd_root 开头的绝对路径,会忽略开头的 / - 无 fpd_root 时必须是绝对路径 - options? @example const prefix_docs = '/zh/' if (path.startsWith(prefix_docs)) { await this.try_send( ctx, (path.endsWith('/') ? `${path}index.html` : path).strip_start(prefix_docs), { fpd_root: `${fpd_temp}docs${prefix_docs}`, }, ) return } */ try_send(ctx: Context, fp: string, { fpd_root, assets_root, sea: _sea, log_404, }?: { fpd_root?: string; assets_root?: string; sea?: boolean; log_404?: boolean; }): Promise; log_404(ctx: Context): void; /** 将 body 设置为 fp 所指文件的 ReadStream 检查 fp 是否合法,设置对应的 content-type,支持缓存,支持分块下载 - ctx: Koa.Context - fp: 文件路径 - 有 fpd_root 时为相对路径或以 fpd_root 开头的绝对路径,会忽略开头的 / - 无 fpd_root 时必须是绝对路径 - options?: - fpd_root?: 只能访问 fpd_root 下面的文件 - absolute?: `false` 使用绝对路径指定发送的文件 - download?: `false` 在 response.headers 中加上 content-disposition: attachment 指示浏览器下载文件 - assets_root?: 替换模板 xxx.template.html 中 {root} 占位符 */ fsend(ctx: Context, fp: string, { fpd_root, absolute, download, assets_root, sea: _sea }?: { fpd_root?: string; absolute?: boolean; download?: boolean; assets_root?: string; sea?: boolean; }): Promise; /** - range: 取值为逗号分割的多个可用端口或端口区间 (不能含有空格,包含区间右值),比如:`8321,8322,8300-8310,11000-11999 - reverse?: `false` 在 range 内从后往前尝试 */ static get_available_port(range: string, reverse?: boolean): Promise; } export type ResponseHeaders = OutgoingHttp2Headers & { ':status'?: string; }; export type RequestHeaders = Exclude; export interface Context { request: { version: 1 | 2 | 3; h1: boolean; h2: boolean; h3: boolean; https: boolean; method: string; /** 经过 decodeURIComponent 后,在路径重写之前的路径 */ _path: string; path: string; search: string; url: string; headers: IncomingHttp2Headers; body: string | Uint8Array | any; local_port: number; host: string; hostname: string; ip: string; queries: Record; cookies: Record; socket?: Socket; get_header(key: TKey): RequestHeaders[TKey]; get_headers(): RequestHeaders; /** 获取 http 请求想要的显示语言,可传入 languages 设置优先级/可选项,默认 ['zh', 'en'] */ get_language(languages?: string[]): string; }; response: { get_status(): number; set_status(code: number): Response; get_header(key: 'set-cookie'): string[]; get_header(key: string): string; get_header(key: string): string | string[]; set_header(key: 'set-cookie', value: string[]): Response; set_header(key: string, value: string): Response; get_headers(): ResponseHeaders; /** 谨慎使用,会完全替换当前所有的 headers_, 包括 :status */ set_headers(values: ResponseHeaders): Response; /** 设置 content-type */ set_type(type: string): Response; get_body(): any; set_body(body: string | Uint8Array | Readable): Response; set_json(obj: any): Response; set_text(text: string): Response; /** 通过设置文件后缀来设置 content-type */ set_fext(fext: string): Response; /** 设置 :status 为 200 */ set_ok(): Response; /** 重定向到完整 url 或者包含 querystring 的路径,设置 status code 为 code - url: 完整 url 或路径 (可以包含 querystring) - code: 301 (永久重定向) | 302 (临时重定向) | 307 (非 GET 请求保持原有方法和 body 的临时重定向) */ redirect(url: string | URL, code: 301 | 302 | 307): Response; set_cookie(key: string, value: string, options: SetCookieOptions): Response; /** 对于 Readable 的 body,设置 body_size 有助于提高压缩性能 */ set_body_size(size: number): Response; }; } export type Request = Context['request']; export type Response = Context['response']; export interface SetCookieOptions { expires?: number | Date; secure?: boolean; path?: string; } interface StdioSubscriber { remote: Remote; id: number; close(): void; } export interface ServerRequestOptions { headers?: Record; queries?: Record; redirect?: RequestOptions['redirect']; timeout?: RequestOptions['timeout']; throw_error?: boolean; proxy?: RequestOptions['proxy']; print_error?: boolean; } /** 简易判断 content-type 是否可压缩, 参考 compressible 模块 */ export declare const compressible_regexp: RegExp; export declare const text_plain: 'text/plain; charset=utf-8'; /** Encode a URL to a percent-encoded form, excluding already-encoded sequences. This function will take an already-encoded URL and encode all the non-URL code points. This function will not encode the "%" character unless it is not part of a valid sequence (`%20` will be left as-is, but `%foo` will be encoded as `%25foo`). This encode is meant to be "safe" and does not throw errors. It will try as hard as it can to properly encode the given URL, including replacing any raw, unpaired surrogate pairs with the Unicode replacement character prior to encoding. @param {string} url @return {string} @public */ export declare function encodeurl(url: any): string; export {};