export interface; -w 时自动监听没有content-type的html

This commit is contained in:
Star 2025-12-10 16:56:37 +08:00
parent 069a4b95c2
commit fa97cace29
3 changed files with 227 additions and 226 deletions

2
go.mod
View File

@ -3,7 +3,7 @@ module apigo.cc/gojs/service
go 1.24.0 go 1.24.0
require ( require (
apigo.cc/gojs v0.0.30 apigo.cc/gojs v0.0.31
apigo.cc/gojs/console v0.0.4 apigo.cc/gojs/console v0.0.4
apigo.cc/gojs/file v0.0.7 apigo.cc/gojs/file v0.0.7
apigo.cc/gojs/http v0.0.8 apigo.cc/gojs/http v0.0.8

View File

@ -290,8 +290,9 @@ func init() {
onWatchLock.Unlock() onWatchLock.Unlock()
}, "") }, "")
s.SetOutFilter(func(in map[string]any, request *s.Request, response *s.Response, out any, logger *log.Logger) (newOut any, isOver bool) { s.SetOutFilter(func(in map[string]any, request *s.Request, response *s.Response, out any, logger *log.Logger) (newOut any, isOver bool) {
if strings.HasPrefix(response.Header().Get("Content-Type"), "text/html") { contentType := response.Header().Get("Content-Type")
outStr := u.String(out) outStr := u.String(out)
if strings.HasPrefix(contentType, "text/html") || (contentType == "" && strings.Contains(outStr, "<html")) {
if strings.Contains(outStr, "let _watchWS = null") { if strings.Contains(outStr, "let _watchWS = null") {
return nil, false return nil, false
} }

View File

@ -1,29 +1,29 @@
// just for develop // just for develop
export default { export default {
config, config,
start, start,
stop, stop,
register, register,
load, load,
// task, // task,
newCaller, newCaller,
// dataSet, // dataSet,
// dataGet, // dataGet,
// dataKeys, // dataKeys,
// dataCount, // dataCount,
// dataFetch, // dataFetch,
// dataRemove, // dataRemove,
// listPush, // listPush,
// listPop, // listPop,
// listCount, // listCount,
// listRemove, // listRemove,
id, id,
// idL, // idL,
// uniqueId, // uniqueId,
// uniqueIdL, // uniqueIdL,
setTplFunc, setTplFunc,
tpl, tpl,
} }
function config(config?: Config): void { } function config(config?: Config): void { }
@ -55,239 +55,239 @@ function id(size?: number): string { return '' }
function setTplFunc(fnList: Object): void { } function setTplFunc(fnList: Object): void { }
function tpl(file: string, data: Object): string { return '' } function tpl(file: string, data: Object): string { return '' }
interface Config { export interface Config {
// github.com/ssgo/s 的配置参数 // github.com/ssgo/s 的配置参数
listen: string // 监听端口(|隔开多个监听)(,隔开多个选项如果不指定IP则监听在0.0.0.0如果不指定端口则使用h2c协议监听在随机端口80端口默认使用http协议443端口默认使用https协议例如 80,http|443|443:h2|127.0.0.1:8080,h2c listen: string // 监听端口(|隔开多个监听)(,隔开多个选项如果不指定IP则监听在0.0.0.0如果不指定端口则使用h2c协议监听在随机端口80端口默认使用http协议443端口默认使用https协议例如 80,http|443|443:h2|127.0.0.1:8080,h2c
ssl: Map<string, CertSet> // SSL证书配置key为域名value为cert和key的文件路径 ssl: Map<string, CertSet> // SSL证书配置key为域名value为cert和key的文件路径
noLogGets: boolean // 不记录GET请求的日志 noLogGets: boolean // 不记录GET请求的日志
noLogHeaders: string // 不记录请求头中包含的这些字段多个字段用逗号分隔默认不记录Accept,Accept-Encoding,Cache-Control,Pragma,Connection,Upgrade-Insecure-Requests noLogHeaders: string // 不记录请求头中包含的这些字段多个字段用逗号分隔默认不记录Accept,Accept-Encoding,Cache-Control,Pragma,Connection,Upgrade-Insecure-Requests
logInputArrayNum: number // 请求字段中容器类型数组、Map在日志打印个数限制 默认为10个多余的数据将不再日志中记录 logInputArrayNum: number // 请求字段中容器类型数组、Map在日志打印个数限制 默认为10个多余的数据将不再日志中记录
logInputFieldSize: number // 请求字段中单个字段在日志打印长度限制 默认为500个字符多余的数据将不再日志中记录 logInputFieldSize: number // 请求字段中单个字段在日志打印长度限制 默认为500个字符多余的数据将不再日志中记录
noLogOutputFields: string // 不记录响应字段中包含的这些字段key名多个字段用逗号分隔 noLogOutputFields: string // 不记录响应字段中包含的这些字段key名多个字段用逗号分隔
logOutputArrayNum: number // 响应字段中容器类型数组、Map在日志打印个数限制 默认为3个多余的数据将不再日志中记录 logOutputArrayNum: number // 响应字段中容器类型数组、Map在日志打印个数限制 默认为3个多余的数据将不再日志中记录
logOutputFieldSize: number // 响应字段中单个字段在日志打印长度限制 默认为100个字符多余的数据将不再日志中记录 logOutputFieldSize: number // 响应字段中单个字段在日志打印长度限制 默认为100个字符多余的数据将不再日志中记录
logWebsocketAction: boolean // 记录Websocket中每个Action的请求日志默认不记录 logWebsocketAction: boolean // 记录Websocket中每个Action的请求日志默认不记录
compress: boolean // 是否启用压缩,默认不启用 compress: boolean // 是否启用压缩,默认不启用
compressMinSize: number // 小于设定值的应答内容将不进行压缩默认值1024 compressMinSize: number // 小于设定值的应答内容将不进行压缩默认值1024
compressMaxSize: number // 大于设定值的应答内容将不进行压缩默认值4096000 compressMaxSize: number // 大于设定值的应答内容将不进行压缩默认值4096000
checkDomain: string // 心跳检测时使用域名默认使用IP地址心跳检测使用 HEAD /__CHECK__ 请求,应答 299 表示正常593 表示异常 checkDomain: string // 心跳检测时使用域名默认使用IP地址心跳检测使用 HEAD /__CHECK__ 请求,应答 299 表示正常593 表示异常
redirectTimeout: number // proxy和discover发起请求时的超时时间单位ms默认值10000 redirectTimeout: number // proxy和discover发起请求时的超时时间单位ms默认值10000
acceptXRealIpWithoutRequestId: boolean // 是否允许头部没有携带请求ID的X-Real-IP信息默认不允许防止伪造客户端IP acceptXRealIpWithoutRequestId: boolean // 是否允许头部没有携带请求ID的X-Real-IP信息默认不允许防止伪造客户端IP
statisticTime: boolean // 是否开启请求时间统计,默认不开启 statisticTime: boolean // 是否开启请求时间统计,默认不开启
statisticTimeInterval: number // 统计时间间隔单位ms默认值10000 statisticTimeInterval: number // 统计时间间隔单位ms默认值10000
fast: boolean // 是否启用快速模式(为了追求性能牺牲一部分特性),默认不启用 fast: boolean // 是否启用快速模式(为了追求性能牺牲一部分特性),默认不启用
maxUploadSize: number // 最大上传文件大小multipart/form-data请求的总空间单位字节默认值104857600 maxUploadSize: number // 最大上传文件大小multipart/form-data请求的总空间单位字节默认值104857600
cpu: number // CPU占用的核数默认为0即不做限制 cpu: number // CPU占用的核数默认为0即不做限制
memory: number // 内存单位M默认为0即不做限制 memory: number // 内存单位M默认为0即不做限制
cpuMonitor: boolean // 在日志中记录CPU使用情况默认不开启 cpuMonitor: boolean // 在日志中记录CPU使用情况默认不开启
memoryMonitor: boolean // 在日志中记录内存使用情况,默认不开启 memoryMonitor: boolean // 在日志中记录内存使用情况,默认不开启
cpuLimitValue: number // CPU超过最高占用值10-100超过次数将自动重启如果CpuMonitor开启的话默认100 cpuLimitValue: number // CPU超过最高占用值10-100超过次数将自动重启如果CpuMonitor开启的话默认100
memoryLimitValue: number // 内存超过最高占用值10-100超过次数将自动重启如果MemoryMonitor开启的话默认95 memoryLimitValue: number // 内存超过最高占用值10-100超过次数将自动重启如果MemoryMonitor开启的话默认95
cpuLimitTimes: number // CPU超过最高占用值超过次数1-100将报警如果CpuMonitor开启的话默认6即30秒内连续6次 cpuLimitTimes: number // CPU超过最高占用值超过次数1-100将报警如果CpuMonitor开启的话默认6即30秒内连续6次
memoryLimitTimes: number // 内存超过最高占用值超过次数1-100将报警如果MemoryMonitor开启的话默认6即30秒内连续6次 memoryLimitTimes: number // 内存超过最高占用值超过次数1-100将报警如果MemoryMonitor开启的话默认6即30秒内连续6次
cookieScope: string // 启用Session时Cookie的有效范围host|domain|topDomain默认值为host cookieScope: string // 启用Session时Cookie的有效范围host|domain|topDomain默认值为host
sessionWithoutCookie: boolean // Session禁用Cookie保持默认使用Cookie sessionWithoutCookie: boolean // Session禁用Cookie保持默认使用Cookie
deviceWithoutCookie: boolean // 设备ID禁用Cookie保持默认使用Cookie deviceWithoutCookie: boolean // 设备ID禁用Cookie保持默认使用Cookie
idServer: string // 用s.UniqueId、s.Id来生成唯一ID雪花算法时所需的redis服务器连接如果不指定将不能实现跨服务的全局唯一 idServer: string // 用s.UniqueId、s.Id来生成唯一ID雪花算法时所需的redis服务器连接如果不指定将不能实现跨服务的全局唯一
keepKeyCase: boolean // 是否保持Key的首字母大小写默认保持设置为false则自动将首字母转为小写 keepKeyCase: boolean // 是否保持Key的首字母大小写默认保持设置为false则自动将首字母转为小写
indexFiles: string[] // 访问静态文件时的索引文件,默认为 index.html indexFiles: string[] // 访问静态文件时的索引文件,默认为 index.html
indexDir: boolean // 访问目录时显示文件列表 indexDir: boolean // 访问目录时显示文件列表
readTimeout: number // 读取请求的超时时间单位ms readTimeout: number // 读取请求的超时时间单位ms
readHeaderTimeout: number // 读取请求头的超时时间单位ms readHeaderTimeout: number // 读取请求头的超时时间单位ms
writeTimeout: number // 响应写入的超时时间单位ms writeTimeout: number // 响应写入的超时时间单位ms
idleTimeout: number // 连接空闲超时时间单位ms idleTimeout: number // 连接空闲超时时间单位ms
maxHeaderBytes: number // 请求头的最大字节数 maxHeaderBytes: number // 请求头的最大字节数
maxHandlers: number // 每个连接的最大处理程序数量 maxHandlers: number // 每个连接的最大处理程序数量
maxConcurrentStreams: number // 每个连接的最大并发流数量 maxConcurrentStreams: number // 每个连接的最大并发流数量
maxDecoderHeaderTableSize: number // 解码器头表的最大大小 maxDecoderHeaderTableSize: number // 解码器头表的最大大小
maxEncoderHeaderTableSize: number // 编码器头表的最大大小 maxEncoderHeaderTableSize: number // 编码器头表的最大大小
maxReadFrameSize: number // 单个帧的最大读取大小 maxReadFrameSize: number // 单个帧的最大读取大小
maxUploadBufferPerConnection: number // 每个连接的最大上传缓冲区大小 maxUploadBufferPerConnection: number // 每个连接的最大上传缓冲区大小
maxUploadBufferPerStream: number // 每个流的最大上传缓冲区大小 maxUploadBufferPerStream: number // 每个流的最大上传缓冲区大小
// 其他配置 // 其他配置
sessionKey: string // HTTP头和Cookie中SessionID的Key客户端没有传递时服务端自动生成Header的优先级高于Cookie默认为 Session, 设置为空时表示不使用 sessionKey: string // HTTP头和Cookie中SessionID的Key客户端没有传递时服务端自动生成Header的优先级高于Cookie默认为 Session, 设置为空时表示不使用
deviceKey: string // 标识设备ID的Key客户端没有传递时服务端自动生成Header的优先级高于Cookie默认为 Device 设置为空时表示不使用 deviceKey: string // 标识设备ID的Key客户端没有传递时服务端自动生成Header的优先级高于Cookie默认为 Device 设置为空时表示不使用
clientKey: string // 标识客户端的Key默认为 Client对应的Header头为 ClientName 和 ClientVersion clientKey: string // 标识客户端的Key默认为 Client对应的Header头为 ClientName 和 ClientVersion
userIdKey: string // session中userID的Key用于在日志中记录用户ID信息默认为 id userIdKey: string // session中userID的Key用于在日志中记录用户ID信息默认为 id
sessionProvider: string // 指定一个redis连接例如redis://:sskey加密的密码@127.0.0.1:6379/15默认使用内存存储 sessionProvider: string // 指定一个redis连接例如redis://:sskey加密的密码@127.0.0.1:6379/15默认使用内存存储
sessionTimeout: number // session过期时间单位 秒,默认为 3600秒 sessionTimeout: number // session过期时间单位 秒,默认为 3600秒
authFieldMessage: string | Object // 身份验证失败时的消息,默认为 auth failed可以设置对象来返回JSON可以使用模版 {{TARGET_AUTHLEVEL}}、{{USER_AUTHLEVEL}} authFieldMessage: string | Object // 身份验证失败时的消息,默认为 auth failed可以设置对象来返回JSON可以使用模版 {{TARGET_AUTHLEVEL}}、{{USER_AUTHLEVEL}}
verifyFieldMessage: string | Object // 参数验证失败时的消息,默认为 verify failed可以设置对象来返回JSON可以使用模版 {{FAILED_FIELDS}} verifyFieldMessage: string | Object // 参数验证失败时的消息,默认为 verify failed可以设置对象来返回JSON可以使用模版 {{FAILED_FIELDS}}
limitedMessage: string | Object // 访问受限时的消息,默认为 too many requests可以设置对象来返回JSON可以使用模版 {{LIMITED_FROM}}、{{LIMITED_VALUE}} limitedMessage: string | Object // 访问受限时的消息,默认为 too many requests可以设置对象来返回JSON可以使用模版 {{LIMITED_FROM}}、{{LIMITED_VALUE}}
limiterRedis: string // 限流器使用的Redis连接默认使用内存存储 limiterRedis: string // 限流器使用的Redis连接默认使用内存存储
limiters: Map<string, LimiterConfig> // 限流器配置from 为数据来源例如ip、user、device、header.User-Agent、in.phone 等in表示从请求参数中获取time为时间间隔单位mstimes为 时间间隔内允许访问的次数 limiters: Map<string, LimiterConfig> // 限流器配置from 为数据来源例如ip、user、device、header.User-Agent、in.phone 等in表示从请求参数中获取time为时间间隔单位mstimes为 时间间隔内允许访问的次数
hotLoad: number // 热加载配置单位s默认值00表示不检测热加载 hotLoad: number // 热加载配置单位s默认值00表示不检测热加载
// gateway 的配置参数 // gateway 的配置参数
proxy: Map<string, string> // 代理配置key为[host][path]value为代理的目标应用或URL proxy: Map<string, string> // 代理配置key为[host][path]value为代理的目标应用或URL
rewrite: Map<string, string> // 重写请求路径key为[host][path]value为重写后的路径 rewrite: Map<string, string> // 重写请求路径key为[host][path]value为重写后的路径
static: Map<string, string> // 静态文件目录key为[host][path]value为目录路径 static: Map<string, string> // 静态文件目录key为[host][path]value为目录路径
// github.com/ssgo/discover 的配置参数 // github.com/ssgo/discover 的配置参数
registry: string // 服务注册中心请配置一个有效的RedisURL默认值 redis://:@127.0.0.1:6379/15 registry: string // 服务注册中心请配置一个有效的RedisURL默认值 redis://:@127.0.0.1:6379/15
app: string // 设置该值将会自动将服务注册到 discover app: string // 设置该值将会自动将服务注册到 discover
weight: number // 节点的权重,默认值 100 weight: number // 节点的权重,默认值 100
accessTokens: Map<string, number> // 请求接口时使用指定的Access-Token进行验证值为Token对应的authLevel允许访问大于等于指定对应authLevel的接口 accessTokens: Map<string, number> // 请求接口时使用指定的Access-Token进行验证值为Token对应的authLevel允许访问大于等于指定对应authLevel的接口
calls: Map<string, string> // 配置将会调用的服务,格式:[1|2]:[http|https|h2c]:[AccessToken]默认协议为h2c如使用h2c协议可只提供 AccessToken calls: Map<string, string> // 配置将会调用的服务,格式:[1|2]:[http|https|h2c]:[AccessToken]默认协议为h2c如使用h2c协议可只提供 AccessToken
callRetryTimes: number // 调用其他服务时最大重试次数,默认值 10 callRetryTimes: number // 调用其他服务时最大重试次数,默认值 10
ipPrefix: string // discover服务发现时指定使用的IP网段默认排除 172.17.Docker ipPrefix: string // discover服务发现时指定使用的IP网段默认排除 172.17.Docker
} }
interface CertSet { export interface CertSet {
certFile: string certFile: string
keyFile: string keyFile: string
} }
interface PoolConfig { export interface PoolConfig {
min: number min: number
max: string max: string
idle: number idle: number
} }
interface LimiterConfig { export interface LimiterConfig {
from: string from: string
time: number time: number
times: number times: number
} }
interface RegisterOption { export interface RegisterOption {
authLevel: number authLevel: number
host: string host: string
method: string method: string
path: string path: string
memo: string memo: string
noBody: boolean noBody: boolean
noLog200: boolean noLog200: boolean
limiters: string[] limiters: string[]
verifies: Object verifies: Object
requires: string[] requires: string[]
ext: Object ext: Object
onMessage: (params: OnMessageParams) => void onMessage: (params: OnMessageParams) => void
onClose: (params: RequestParams) => void onClose: (params: RequestParams) => void
} }
interface RequestParams { export interface RequestParams {
args: Object args: Object
headers: Object headers: Object
request: Request request: Request
client: WSClient client: WSClient
caller: Caller caller: Caller
session: Session session: Session
response: Response response: Response
logger: Logger logger: Logger
} }
interface OnMessageParams { export interface OnMessageParams {
type: string type: string
data: string | Object data: string | Object
client: WSClient client: WSClient
session: Session session: Session
logger: Logger logger: Logger
} }
interface WSClient { export interface WSClient {
id: string id: string
read: () => WSMessage read: () => WSMessage
write: (data: any) => void write: (data: any) => void
writeMessage: (type: string, data: any) => void writeMessage: (type: string, data: any) => void
ping: () => void ping: () => void
close: () => void close: () => void
} }
interface WSMessage { export interface WSMessage {
type: string type: string
data: string | Object data: string | Object
} }
interface Session { export interface Session {
set: (key: string | Object, value?: any) => void set: (key: string | Object, value?: any) => void
get: (...keys: string[]) => any | Object get: (...keys: string[]) => any | Object
remove: (...keys: string[]) => void remove: (...keys: string[]) => void
setAuthLevel: (authLevel: number) => void setAuthLevel: (authLevel: number) => void
save: () => void save: () => void
} }
interface Caller { export interface Caller {
get(url: string, headers?: Object): Result get(url: string, headers?: Object): Result
head(url: string, headers?: Object): Result head(url: string, headers?: Object): Result
post(url: string, data: any, headers?: Object): Result post(url: string, data: any, headers?: Object): Result
put(url: string, data: any, headers?: Object): Result put(url: string, data: any, headers?: Object): Result
delete(url: string, data: any, headers?: Object): Result delete(url: string, data: any, headers?: Object): Result
do(method: string, url: string, data: any, callback?: (data: string) => void, headers?: Object): Result do(method: string, url: string, data: any, callback?: (data: string) => void, headers?: Object): Result
} }
interface Result { export interface Result {
status: string status: string
statusCode: number statusCode: number
headers: Object headers: Object
bytes(): Uint8Array bytes(): Uint8Array
string(): string string(): string
object(): Object object(): Object
} }
interface CookieOption { export interface CookieOption {
path: string path: string
domain: string domain: string
expires: any expires: any
maxAge: number maxAge: number
secure: boolean secure: boolean
httpOnly: boolean httpOnly: boolean
} }
interface Request { export interface Request {
id: string id: string
proto: string proto: string
scheme: string scheme: string
host: string host: string
method: string method: string
path: string path: string
remoteAddr: string remoteAddr: string
realIP: string realIP: string
referer: string referer: string
userAgent: string userAgent: string
url: string url: string
contentLength: number contentLength: number
cookies: Object cookies: Object
headers: Object headers: Object
args: Object args: Object
files: Map<string, UploadFile> files: Map<string, UploadFile>
multiFiles: Map<string, UploadFile[]> multiFiles: Map<string, UploadFile[]>
makeURL: (path: string) => string makeURL: (path: string) => string
readAll: () => any readAll: () => any
read: (size: number) => any read: (size: number) => any
close: () => void close: () => void
get: (key: string) => any get: (key: string) => any
set: (key: string, value: any) => void set: (key: string, value: any) => void
getHeader: (key: string) => string getHeader: (key: string) => string
setHeader: (key: string, value: string) => void setHeader: (key: string, value: string) => void
setUserID: (id: string) => void setUserID: (id: string) => void
} }
interface Response { export interface Response {
id: string id: string
setStatus: (code: number) => void setStatus: (code: number) => void
setCookie: (name: string, value: string, option?: CookieOption) => void setCookie: (name: string, value: string, option?: CookieOption) => void
setHeader: (name: string, value: string) => void setHeader: (name: string, value: string) => void
addHeader: (name: string, value: string) => void addHeader: (name: string, value: string) => void
getHeader: (name: string) => string getHeader: (name: string) => string
write: (data: any) => number write: (data: any) => number
flush: () => void flush: () => void
sendFile: (contentType: string, filename: string) => void sendFile: (contentType: string, filename: string) => void
downloadFile: (contentType: string, filename: string, data: any) => void downloadFile: (contentType: string, filename: string, data: any) => void
location: (url: string) => void location: (url: string) => void
end: (data: any) => void end: (data: any) => void
} }
interface Logger { export interface Logger {
debug: (message: string, info?: Object) => void debug: (message: string, info?: Object) => void
info: (message: string, info?: Object) => void info: (message: string, info?: Object) => void
warn: (message: string, info?: Object) => void warn: (message: string, info?: Object) => void
error: (message: string, info?: Object) => void error: (message: string, info?: Object) => void
} }
interface UploadFile { export interface UploadFile {
name: string name: string
size: number size: number
data: any data: any
} }