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' }