web 访问网络
web 是 Alia 的标准库网络模块,提供 URL 解析、HTTP 客户端/服务端、MIME 类型查询等功能。
引入模块
import 'web' as web ~ 导入为变量
import 'web' ~ 导入作用域
URL 工具
urlParse
解析 URL 字符串为结构化对象。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 第一位置参数 | String | 是 | 需要解析的 URL 字符串 |
返回对象属性:
| 属性 | 类型 | 说明 |
|---|---|---|
protocol | String | 协议,如 'https' |
host | String | 主机名+端口,如 'example.com:8080' |
hostname | String | 主机名,如 'example.com' |
port | Number? | 端口号,无则为 null |
pathname | String | 路径,如 '/path' |
search | String? | 查询字符串,无则为 null |
hash | String? | 锚点,无则为 null |
href | String | 完整 URL |
const parsed = web.urlParse 'https://example.com:8080/path?key=value#anchor'
parsed.protocol ~ 'https'
parsed.hostname ~ 'example.com'
parsed.port ~ 8080
parsed.pathname ~ '/path'
parsed.search ~ '?key=value'
parsed.hash ~ '#anchor'
urlBuild
从结构化对象构建 URL 字符串。urlBuild 是 urlParse 的逆操作。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 第一位置参数 | Object | 是 | 包含 URL 各部分的对象 |
const url = call web.urlBuild *[
protocol: 'https',
hostname: 'example.com',
port: 8080,
pathname: '/api',
search: '?q=alia'
]
~ 'https://example.com:8080/api?q=alia'
urlEncode / urlDecode
对整个 URL 进行编码/解码(保留 ://、?、# 等 URL 保留字符)。
web.urlEncode 'https://example.com/路径'
~ 'https://example.com/%E8%B7%AF%E5%BE%84'
web.urlDecode 'https://example.com/%E8%B7%AF%E5%BE%84'
~ 'https://example.com/路径'
urlEncodeComponent / urlDecodeComponent
对 URI 组件进行编码/解码(会编码所有特殊字符)。
web.urlEncodeComponent 'hello world'
~ 'hello%20world'
web.urlDecodeComponent 'hello%20world'
~ 'hello world'
MIME 类型
mimeGet
根据文件扩展名获取对应的 MIME 类型。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 第一位置参数 | String | 是 | 文件扩展名(可带或不带 . 前缀) |
web.mimeGet 'json' ~ 'application/json'
web.mimeGet '.html' ~ 'text/html'
web.mimeGet 'png' ~ 'image/png'
web.mimeGet 'xyz' ~ 'application/octet-stream' ~ 未知类型默认值
内置 MIME 映射表:
| 扩展名 | MIME 类型 |
|---|---|
html, htm | text/html |
css | text/css |
js, mjs | application/javascript |
json | application/json |
xml | application/xml |
txt | text/plain |
csv | text/csv |
png | image/png |
jpg, jpeg | image/jpeg |
gif | image/gif |
svg | image/svg+xml |
ico | image/x-icon |
webp | image/webp |
mp3 | audio/mpeg |
wav | audio/wav |
ogg | audio/ogg |
mp4 | video/mp4 |
webm | video/webm |
pdf | application/pdf |
zip | application/zip |
gz | application/gzip |
tar | application/x-tar |
wasm | application/wasm |
ttf | font/ttf |
woff | font/woff |
woff2 | font/woff2 |
yaml, yml | application/x-yaml |
md | text/markdown |
mimeGetExtension
根据 MIME 类型获取首选文件扩展名。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 第一位置参数 | String | 是 | MIME 类型字符串 |
web.mimeGetExtension 'text/html' ~ 'html'
web.mimeGetExtension 'application/json' ~ 'json'
web.mimeGetExtension 'application/x-unknown' ~ null
HTTP 客户端
httpRequest
发起异步 HTTP 请求。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 第一位置参数 | Object | 是 | 请求选项对象 |
请求选项对象属性:
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
url | String | 是 | - | 请求 URL |
method | String | 否 | 'GET' | HTTP 方法 |
headers | Object | 否 | {} | 请求头 |
body | String | 否 | null | 请求体 |
timeout | Number | 否 | 30000 | 超时时间(毫秒) |
返回 Stack(异步请求对象,需 await 消费):
发起请求后返回符合 Alia 异步模型的可 await Stack。请求在后台线程执行,await 等待结果,响应对象可通过 task.response 访问。
| 属性 | 类型 | 说明 |
|---|---|---|
status | Number | HTTP 状态码 |
statusText | String | 状态文本 |
headers | Object | 响应头 |
body | String | 响应体 |
ok | Boolean | 状态码 200-299 时为 true |
const opts = *[
method: 'GET',
url: 'https://api.example.com/data'
]
const resp = await web.httpRequest opts
if (resp.ok as Boolean) {
print resp.body as String
}
await 接受返回 Stack 的表达式,可一步到位取得响应;也可先持有任务句柄再等待,以便访问 isRunning/isDone/detach:
const task = web.httpRequest opts
await task
if (task.response.ok as Boolean) {
print task.response.body as String
}
在线检测
推荐以 https://alia.0832.ink/externalAccess 静态探针判定在线:该文件部署于文档站,内容为 true。
import 'web' as web
const opts = *[url: 'https://alia.0832.ink/externalAccess', timeout: 10000]
const task = web.httpRequest opts
await task
assert (Ok task.response.body) error 'externalAccess should return body'
assert (call task.response.body.trim) == 'true' error 'externalAccess should be true'
assert task.response.status == 200 error 'externalAccess should return 200'
离线时请求失败/回退为 HTML,非 true。
serverCreate
创建 HTTP 服务器实例。
const server = call web.serverCreate
返回 Server 对象方法:
server.addRoute
注册路由处理函数。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 第一位置参数 | String | 是 | HTTP 方法(GET、POST 等)或 * 匹配所有 |
| 第二位置参数 | String | 是 | 路径模式,支持 :param 动态参数 |
| 第三位置参数 | Alias | 是 | 请求处理函数 (req, res) -> { ... } |
server.addRoute 'GET' '/hello' (alias -> <Object req> and <Object res> {
res.send 'Hello, World!'
})
server.addRoute 'GET' '/users/:id' (alias -> <Object req> and <Object res> {
call res.json *[userId: (req.params as Object)['id']]
})
server.addRoute 'POST' '/api/data' (alias -> <Object req> and <Object res> {
~ req.body 包含请求体
call res.json *[received: true]
})
请求对象(req)属性:
| 属性 | 类型 | 说明 |
|---|---|---|
method | String | HTTP 方法 |
url | String | 原始 URL |
path | String | 路径部分 |
query | Object | 查询参数 |
headers | Object | 请求头 |
body | String? | 请求体 |
params | Object? | 路径参数 |
响应对象(res)方法:
| 方法 | 说明 |
|---|---|
res.setStatus code | 设置状态码,默认 200 |
res.setHeader name value | 设置响应头 |
res.send bodyText | 发送文本响应 |
res.json data | 发送 JSON 响应(自动设 Content-Type) |
res.end | 结束响应 |
server.listen
启动服务器监听指定端口。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| 第一位置参数 | Number | 是 | 监听端口号 |
callback | Alias | 否 | 启动成功后的回调 |
server.listen 3000 (alias -> {
io.print 'Server running on http://localhost:3000'
})
server.close
关闭服务器(发起式、非阻塞:调用即发起关闭,端口资源异步释放)。
server.close
完整示例
import 'web' as web
import 'io' as io
~ URL 解析
const parsed = web.urlParse 'https://example.com/search?q=alia'
print '主机: ' .. parsed.hostname
print '路径: ' .. parsed.pathname
~ HTTP 客户端(异步)
const opts = *[
url: 'https://api.github.com'
]
const task = web.httpRequest opts
await task
print '状态码: ' .. (task.response.status as Number)
~ HTTP 服务器
const server = call web.serverCreate
server.addRoute 'GET' '/api/hello' (alias -> <Object req> and <Object res> {
call res.json *[greeting: 'Hello from Alia!']
})
server.listen 3000
io.print '服务器已启动,访问 http://localhost:3000/api/hello'