Skip to content

Commit

Permalink
fix: response's contentType normalized.
Browse files Browse the repository at this point in the history
  • Loading branch information
chizuki committed Mar 7, 2023
1 parent 79c004a commit 3badf7d
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 26 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/polyfill/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function getHeaderValue(
headers: PolyfillHeaderInit,
key: string,
defaultValue?: string
) {
): typeof defaultValue extends undefined ? string | undefined : string {
return getHeader(flatHeaders(headers), key)?.[1] ?? defaultValue;
}

Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ export function defineRouter(

const meta: Record<string, any> = { ...options.meta };

const matcher = createRouteMatcher<FourzeRoute>();
const matcher = createRouteMatcher<FourzeRoute>({
notAllowedRaiseError: true
});

const logger = createLogger("@fourze/core");

Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/shared/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export class FourzeError extends Error {
this.statusCode = code;
} else if (isError(code)) {
super(code.message);
if (isFourzeError(code)) {
this.statusCode = code.statusCode;
}
} else {
super(code);
}
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/shared/matcher.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { FourzeError } from "./error";
import type { RequestMethod } from "./request";

interface RouteMatcher<T = any> {
Expand Down Expand Up @@ -44,6 +45,7 @@ function createRouteNode<T>(options: Partial<RouteNode<T>> = {}): RouteNode<T> {
export interface RouteMatcherOptions {
caseSensitive?: boolean
strictTrailingSlash?: boolean
notAllowedRaiseError?: boolean
}

/**
Expand All @@ -68,9 +70,9 @@ export function createRouteMatcher<T>(options: RouteMatcherOptions = {}): RouteM
add(path: string, method: RequestMethod | "all", payload: any) {
method = method.toLowerCase() as RequestMethod;
path = normalizePath(path);
const segments = path.split("/");

let currentNode = rootNode;
const segments = path.split("/");
let _unnamedPlaceholderCtr = 0;
let isStaticRoute = true;

Expand Down Expand Up @@ -167,7 +169,9 @@ export function createRouteMatcher<T>(options: RouteMatcherOptions = {}): RouteM
if (data) {
return [data, paramsFound ? params : null];
}

if (currentNode.payload.size > 0 && options.notAllowedRaiseError) {
throw new FourzeError(405, "Method Not Allowed");
}
return [null, null];
},
remove(path: string, method: RequestMethod | "all" = "all") {
Expand Down
50 changes: 32 additions & 18 deletions packages/core/src/shared/response.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { OutgoingMessage, ServerResponse } from "http";
import { createLogger } from "../logger";
import { PolyfillServerResponse, getHeaderValue } from "../polyfill";
import { isDef, isObject, isString, isUint8Array } from "../utils";
import { defineOverload, isDef, isObject, isString, isUint8Array } from "../utils";
import { FourzeError } from "./error";
import type { PropType } from "./props";
import type { FourzeRequest } from "./request";

export interface FourzeResponseOptions {
Expand Down Expand Up @@ -38,6 +38,9 @@ export interface FourzeResponse extends FourzeBaseResponse {
*/
send(payload: any, contentType?: string | null): this

send(payload: any, statusCode?: number): this

send(payload: any, statusCode?: number, contentType?: string | null): this
/**
* 获取Content-Type
* @param payload 如果没有指定contentType,则会根据payload的类型自动推断
Expand Down Expand Up @@ -86,7 +89,6 @@ export interface FourzeResponse extends FourzeBaseResponse {
export function createResponse(options: FourzeResponseOptions) {
const res = options?.response;
const response = (res ?? (new PolyfillServerResponse())) as FourzeResponse;
const logger = createLogger("@fourze/core");

let _payload: any;
let _error: FourzeError;
Expand All @@ -99,7 +101,7 @@ export function createResponse(options: FourzeResponseOptions) {
};

response.getContentType = function (data) {
let contentType: string = getHeaderValue(this.getHeaders(), "Content-Type");
let contentType = getHeaderValue(this.getHeaders(), "Content-Type");
if (!contentType && isDef(data)) {
if (isUint8Array(data)) {
contentType = "application/octet-stream";
Expand All @@ -112,9 +114,26 @@ export function createResponse(options: FourzeResponseOptions) {
return contentType;
};

response.send = function (payload: any, contentType?: string) {
contentType = contentType ?? this.getContentType(payload);
switch (contentType) {
const overloadSend = defineOverload({
payload: {
type: [String, Number, Boolean, Uint8Array, Object, null, undefined] as PropType<any>
},
statusCode: {
type: Number
},
contentType: {
type: String
}
});

response.send = function (...args: any[]) {
let { payload, statusCode, contentType } = overloadSend(args);

statusCode ??= this.statusCode ?? 200;
contentType ??= this.getContentType(payload);

const normalizedContentType = contentType?.split(";")[0];
switch (normalizedContentType) {
case "application/json":
payload = JSON.stringify(payload);
break;
Expand All @@ -126,11 +145,10 @@ export function createResponse(options: FourzeResponseOptions) {
break;
}
if (contentType) {
response.setContentType(contentType);
this.setContentType(contentType);
}
_payload = payload;
this.end(_payload);
return this;
return this.status(statusCode).end(payload);
};

response.status = function (code) {
Expand All @@ -140,9 +158,7 @@ export function createResponse(options: FourzeResponseOptions) {

response.sendError = function (...args: any[]) {
_error = new FourzeError(...args);
this.statusCode = _error.statusCode;
logger.error(_error);
return this.send(_error);
return this.send(_error, _error.statusCode);
};

response.appendHeader = function (
Expand Down Expand Up @@ -181,10 +197,9 @@ export function createResponse(options: FourzeResponseOptions) {
};

response.redirect = function (url: string) {
this.statusCode = 302;
this.setHeader("Location", url);
this.end();
return this;
return this.setHeader("Location", url)
.status(302)
.end();
};

response.done = function () {
Expand Down Expand Up @@ -235,7 +250,6 @@ export function createResponse(options: FourzeResponseOptions) {
},
enumerable: true
},

method: {
get() {
return options.method;
Expand Down
24 changes: 20 additions & 4 deletions packages/middlewares/src/middlewares/resolve.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { MaybePromise } from "maybe-types";
import type { FourzeMiddleware, PropType } from "@fourze/core";
import { defineMiddleware, isError, isUndef, overload } from "@fourze/core";
import { defineMiddleware, defineOverload, isError, isUndef, overload } from "@fourze/core";

type ResolveFunction = (data: any, contentType?: string | null) => MaybePromise<any>;

Expand Down Expand Up @@ -42,10 +42,26 @@ export function createResolveMiddleware(
throw new Error("Missing resolve function");
}

const overloadSend = defineOverload({
payload: {
type: [String, Number, Boolean, Uint8Array, Object, null, undefined] as PropType<any>
},
statusCode: {
type: Number
},
contentType: {
type: String
}
});

return defineMiddleware("Response-Resolve", -1, async (req, res, next) => {
const _send = res.send.bind(res);
res.send = function (payload, contentType) {
contentType = contentType ?? req.meta.contentType ?? res.getContentType(payload);
res.send = function (...args: any[]) {
let { payload, statusCode, contentType } = overloadSend(args);

statusCode ??= res.statusCode;
contentType ??= res.getContentType(payload);

const useResolve = res.getHeader(RESOLVE_HEADER) as string;
const isAllow = (isUndef(useResolve) || !["false", "0", "off"].includes(useResolve));

Expand All @@ -57,7 +73,7 @@ export function createResolveMiddleware(
}
}

_send(payload, contentType);
_send(payload, statusCode, contentType);
return res;
};

Expand Down

0 comments on commit 3badf7d

Please sign in to comment.