HTTP Requests

Request 对象(rq)在每一个 Controller 方法以及每一个 app.get/post 回调中都可以使用。它提供了对完整 HTTP 请求以及所有响应辅助方法的访问。

Accessing the Request

在 Controller 子类内部:

class MyController extends Controller {
  Future<String> index() async {
    // rq 可以直接作为 getter 使用
    var name = rq.get<String>('name', def: 'World');
    return rq.renderString(text: 'Hello $name');
  }
}

在内联的 app.get() / app.post() 回调中,rq 是该函数的参数:

app.get(
  path: '/hello',
  index: (rq) async {
    var name = rq.get<String>('name', def: 'World');
    return rq.renderString(text: 'Hello $name');
  },
);

在匿名的 FinchRoute index 闭包中,使用 Context.rq:

FinchRoute(
  key: 'hello',
  path: 'hello',
  index: () async {
    var name = Context.rq.get<String>('name', def: 'World');
    return Context.rq.renderString(text: 'Hello $name');
  },
),

Reading Input Data

GET and POST fields

rq.get<T>(key, {T? def, trim = true}) 用于从 GET 查询参数或 POST 请求体字段中读取数据:

var name    = rq.get<String>('name', def: 'anonymous');
var age     = rq.get<int>('age', def: 0);
var active  = rq.get<bool>('active', def: false);

检查某个字段是否存在:

if (rq.hasData('name')) { ... }

URL path parameters

对于像 users/{id} 这样的路径,使用 rq.getParam() 读取:

var id = rq.getParam('id');
// 如果该参数不存在,则返回 null

Adding parameters manually

addParam / addParams 会将数据注入请求上下文,使其在模板中可用:

rq.addParam('user', user.toJson());
rq.addParams({
  'title': 'Dashboard',
  'year': DateTime.now().year,
});

在 Jinja 模板中:{{ user.name }}、{{ title }}

Request Properties

属性 / 方法 类型 描述
rq.method String HTTP 方法(GET、POST、……)
rq.isPost bool 方法为 POST 时为 true
rq.uri Uri 完整的请求 URI
rq.headers HttpHeaders HTTP 请求头
rq.authorization Authorization 已解析的 Authorization 请求头
rq.cookies List<Cookie> 请求中的 cookie
rq.session HttpSession 服务端 session
rq.isApiEndpoint bool 当路径以 /api/ 开头时为 true
rq.clientIP String 客户端 IP 地址
rq.route FinchRoute? 匹配到的路由(拥有 permissions、key 等属性)
rq.getLanguage() String 当前语言代码(en、fa、……)

Cookies

getCookie/addCookie 默认会对值进行加密和解密(两者的 safe 参数都默认为 true)——如需明文、可直接阅读的 cookie 值,需要显式传入 safe: false:

// 加密(默认)——该值在浏览器中不可读、也无法被篡改
var token = rq.getCookie('auth_token', def: '');
rq.addCookie('auth_token', 'abc123');

// 明文——该值原样存储,在浏览器的开发者工具中可见
var theme = rq.getCookie('theme', def: 'light', safe: false);
rq.addCookie('theme', 'dark', safe: false);

// 删除一个 cookie
rq.removeCookie('theme');

加密密钥是 FinchConfigs.cookiePassword。addCookie 还接受 duration、expires、path、domain、secure、httpOnly 和 sameSite 参数,用于完整控制 Set-Cookie 响应头。完整参考请参阅 Cookies and Sessions。

Sessions

// 读取
var userEmail = rq.getSession('user', def: '');

// 写入
rq.addSession('user', '[email protected]');

// 删除
rq.session.remove('user');

Redirects

// 重定向到相对路径
return rq.redirect('/login');

// 重定向到完整 URL
return rq.redirect('https://example.com');

// 使用指定的状态码
return rq.redirect('/dashboard', status: 301);

Response Methods Summary

方法 Content-Type 描述
renderView(path: '...') text/html 渲染 Jinja 模板文件
renderData(data: {...}) application/json JSON 响应
renderString(text: '...') text/plain 纯文本
renderHtml(html: '...') text/html HTML 字符串
renderTag(tag: Tag) text/html 渲染 Htmler Tag
renderError(404) 视情况而定 标准错误页面或 JSON
renderSSE(stream) text/event-stream Server-Sent Events
renderSocket() — WebSocket 握手占位符

renderView

rq.addParams({'title': 'Home', 'items': items});
return rq.renderView(path: 'pages/home');
// 加载路径:widgetsPath + '/pages/home.' + widgetsType

renderData (JSON)

return rq.renderData(data: {'success': true, 'count': 10});

renderError

// HTML 错误页面
return rq.renderError(404);

// JSON 错误(用于 API 路由)
return rq.renderError(403, toData: true, params: {'message': 'Forbidden'});

renderSSE (Server-Sent Events)

Future<String> sseExample() async {
  Stream<String> streamer = Stream.periodic(
    Duration(seconds: 1),
    (count) => 'Message $count\n',
  ).take(10);

  return rq.renderSSEString(streamer);
}