marble.js
Effects
效果是整个框架的主要组成部分。 它只是一个返回事件流的函数。 使用其通用接口,我们可以定义API端点,事件处理程序或中间件。
HttpEffect它的职责是将每个传入请求映射到响应对象。
美元符号:sometimes used by convention to indicate that a variable holds an Observable or that a function will return an Observable.
中间件
定义中间件:
import { HttpMiddlewareEffect } from '@marblejs/core'; import { tap } from 'rxjs/operators'; export const logger$: HttpMiddlewareEffect = (req$, res) => req$.pipe( tap(req => console.log(`hhh ${req.method} ${req.url}`)), );
导入使用:
import { httpListener } from '@marblejs/core'; import { logger$ } from './middleware/logger' import { bodyParser$ } from '@marblejs/middleware-body'; import { api$ } from './api.effects'; const middlewares = [ logger$, bodyParser$(), ]; const effects = [ api$, ]; export const listener = httpListener({ middlewares, effects, });
这样每进来一个请求就会打印出method和url。
带参数的中间件
interface LoggerOpts { showUrl?: boolean; } export const logger$ = (opts: LoggerOpts = {}): HttpMiddlewareEffect => req$ => req$.pipe( tap(req => console.log(`${req.method} ${opts.showUrl ? req.url : ''}`)), );
使用的时候带上参数:
const middlewares = [ logger$({showUrl: false}), ];
这样就不会打印出url。
提前响应
给req提供了一个req.response.send来提前响应http,官网上写的req.res,测试发现没有res这个字段。
import { HttpMiddlewareEffect } from '@marblejs/core'; import { mergeMap } from 'rxjs/operators'; export const earlier$: HttpMiddlewareEffect = req$ => req$.pipe( mergeMap(req => req.response.send({body: "earlier response!", status: 200})), );
const middlewares = [ earlier$, logger$({showUrl: false}), bodyParser$(), ];
如果被提前返回了响应,那接下来的中间件都不会执行了。
在 API Effects 中使用中间件
比如把之前的earlier$从middlewares数组中删掉,然后在api.effects中引用。
import { r } from '@marblejs/core'; import { mapTo } from 'rxjs/operators'; import { earlier$ } from "./middleware/earlier" export const api$ = r.pipe( r.matchPath('/'), r.matchType('GET'), r.use(earlier$), r.useEffect(req$ => req$.pipe( mapTo({ body: 'Hello, world!' }), )));
这个时候,同样会返回earlier$中的内容,而不是接下来的Hello, world!
路由
api.effects.ts定义成这样:
import { r, combineRoutes } from "@marblejs/core"; import { mapTo } from "rxjs/operators"; // import { earlier$ } from "./middleware/earlier" const getRoot$ = r.pipe( r.matchPath("/"), r.matchType("GET"), r.useEffect(req$ => req$.pipe(mapTo({ body: "Hello, world!" }))) ); const getUser$ = r.pipe( r.matchPath("/user"), r.matchType("GET"), r.useEffect(req$ => req$.pipe(mapTo({ body: "get user" }))) ); export const api$ = combineRoutes("/", [getRoot$, getUser$]);
通过combineRoutes来组合Effects ,这样就能响应/和/user了。combineRoutes表示当前的根路径,后面跟的Effects中匹配的都是该路径下的子路径。
带参数的url
增加一个Effects如下:参数都被放在req.params下。
const getUserInfo$ = r.pipe( r.matchPath("/user/:username"), r.matchType("GET"), r.useEffect(req$ => req$.pipe( tap(req => console.log("req.params === ", req.params)), pluck('params', 'username'), map(username => ({ body: `get user ${username}` })))) ); export const api$ = combineRoutes("/", [getRoot$, getUser$, getUserInfo$]);
根据不同的username返回不同的内容。
查询参数
修改getUser$
const getUser$ = r.pipe( r.matchPath("/user"), r.matchType("GET"), r.useEffect(req$ => req$.pipe( tap(req => console.log(req.query)), mapTo({ body: "get user" }))) );
请求:/user?name=kobe
解析得到:{ name: 'kobe' }