Skip to content

Commit 1cd44ff

Browse files
committed
fix(cos): support ignoreHtmlExt
1 parent c877a10 commit 1cd44ff

File tree

5 files changed

+116
-35
lines changed

5 files changed

+116
-35
lines changed

__tests__/cos.test.ts

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,14 @@ describe('Cos', () => {
6565
force: true,
6666
protocol: 'https',
6767
replace: true,
68+
ignoreHtmlExt: false,
6869
acl: {
6970
permissions: 'public-read',
7071
},
7172
};
7273
const cos = new Cos(credentials, process.env.REGION);
7374

74-
test('should deploy Cos fail', async () => {
75+
test('[cos] deploy cos fail', async () => {
7576
try {
7677
const res = await cos.deploy({ ...inputs, bucket: '1234567890' });
7778
expect(res).toBe(undefined);
@@ -81,7 +82,7 @@ describe('Cos', () => {
8182
}
8283
});
8384

84-
test('should convert error correct', async () => {
85+
test('[cos] convert error correct', async () => {
8586
expect(
8687
convertCosError({
8788
message: 'message',
@@ -103,25 +104,25 @@ describe('Cos', () => {
103104
).toBe('message');
104105
});
105106

106-
test('should deploy Cos success', async () => {
107+
test('[cos] should deploy cos', async () => {
107108
const res = await cos.deploy(inputs);
108109
await sleep(1000);
109110
const reqUrl = `https://${bucket}.cos.${process.env.REGION}.myqcloud.com/index.html`;
110111
const { data } = await axios.get(reqUrl);
111112
expect(res).toEqual(inputs);
112-
expect(data).toMatch(/Serverless\sFramework/gi);
113+
expect(data).toMatch(/Serverless/gi);
113114
});
114115

115-
test('should deploy Cos success again (update)', async () => {
116+
test('[cos] deploy cos again (update)', async () => {
116117
const res = await cos.deploy(inputs);
117118
await sleep(1000);
118119
const reqUrl = `https://${bucket}.cos.${process.env.REGION}.myqcloud.com/index.html`;
119120
const { data } = await axios.get(reqUrl);
120121
expect(res).toEqual(inputs);
121-
expect(data).toMatch(/Serverless\sFramework/gi);
122+
expect(data).toMatch(/Serverless/gi);
122123
});
123124

124-
test('should Cos getObjectUrl success', async () => {
125+
test('[cos] getObjectUrl', async () => {
125126
const res = await cos.getObjectUrl({
126127
bucket,
127128
object: 'index.html',
@@ -131,7 +132,7 @@ describe('Cos', () => {
131132
expect(res).toMatch(/http/);
132133
});
133134

134-
test('should deploy website success', async () => {
135+
test('[website - default] deploy website', async () => {
135136
const res = await cos.website(websiteInputs);
136137

137138
await sleep(2000);
@@ -142,13 +143,26 @@ describe('Cos', () => {
142143
await axios.get(`${reqUrl}/error.html`);
143144
} catch (e) {
144145
expect(e.response.status).toBe(404);
145-
expect(e.response.data).toMatch(/Serverless\sFramework/gi);
146+
expect(e.response.data).toMatch(/Serverless/gi);
146147
}
147148
expect(res).toBe(websiteUrl);
148-
expect(data).toMatch(/Serverless\sFramework/gi);
149+
expect(data).toMatch(/Serverless/gi);
149150
});
150151

151-
test('should deploy website and error code with 200', async () => {
152+
test('[website - ignoreHtmlExt] deploy website', async () => {
153+
websiteInputs.ignoreHtmlExt = true;
154+
const res = await cos.website(websiteInputs);
155+
156+
await sleep(1000);
157+
const websiteUrl = `${inputs.bucket}.cos-website.${process.env.REGION}.myqcloud.com`;
158+
const reqUrl = `${websiteInputs.protocol}://${websiteUrl}/test`;
159+
const { data } = await axios.get(reqUrl);
160+
expect(res).toBe(websiteUrl);
161+
expect(data).toMatch(/Serverless/gi);
162+
expect(data).toMatch(/Test/gi);
163+
});
164+
165+
test('[website - disableErrorStatus] deploy website and error code with 200', async () => {
152166
websiteInputs.disableErrorStatus = true;
153167

154168
const res = await cos.website(websiteInputs);
@@ -158,22 +172,22 @@ describe('Cos', () => {
158172
const reqUrl = `${websiteInputs.protocol}://${websiteUrl}`;
159173
const { data, status } = await axios.get(`${reqUrl}/error.html`);
160174
expect(res).toBe(websiteUrl);
161-
expect(data).toMatch(/Serverless\sFramework/gi);
175+
expect(data).toMatch(/Serverless/gi);
162176
expect(status).toBe(200);
163177
});
164178

165-
test('should deploy Cos success with policy', async () => {
179+
test('[cos - policy] deploy Cos success with policy', async () => {
166180
inputs.acl.permissions = 'private';
167181
inputs.policy = policy;
168182
const res = await cos.deploy(inputs);
169183
await sleep(1000);
170184
const reqUrl = `https://${bucket}.cos.${process.env.REGION}.myqcloud.com/index.html`;
171185
const { data } = await axios.get(reqUrl);
172186
expect(res).toEqual(inputs);
173-
expect(data).toMatch(/Serverless\sFramework/gi);
187+
expect(data).toMatch(/Serverless/gi);
174188
});
175189

176-
test('should deploy website success with policy', async () => {
190+
test('[website - policy] deploy website success with policy', async () => {
177191
websiteInputs.acl.permissions = 'private';
178192
websiteInputs.policy = policy;
179193
const res = await cos.website(websiteInputs);
@@ -182,10 +196,10 @@ describe('Cos', () => {
182196
const reqUrl = `${websiteInputs.protocol}://${websiteUrl}`;
183197
const { data } = await axios.get(reqUrl);
184198
expect(res).toBe(websiteUrl);
185-
expect(data).toMatch(/Serverless\sFramework/gi);
199+
expect(data).toMatch(/Serverless/gi);
186200
});
187201

188-
test('should remove Cos success', async () => {
202+
test('[cos] remove success', async () => {
189203
await cos.remove(inputs);
190204
try {
191205
await cos.getBucket({

__tests__/static/index.html

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
<head>
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6-
<title>Serverless Component - Website</title>
6+
<meta name="description" content="Serverless Website 应用" />
7+
<meta name="keywords" content="website,serverless,无服务" />
8+
<title>Serverless - Website</title>
79
<style lang="css">
810
h1 {
911
text-align: center;
@@ -14,8 +16,12 @@
1416
</head>
1517
<body>
1618
<h1>
17-
Welcome to website created by
18-
<a href="https://serverlesscloud.cn/">Serverless Framework.</a>
19+
欢迎访问静态网站
20+
<br />
21+
<a href="https://cloud.tencent.com/product/sls" target="_blank" rel="noopener noreferrer">
22+
腾讯云 Serverless
23+
</a>
24+
为您提供服务
1925
</h1>
2026
</body>
2127
</html>

__tests__/static/test.html

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<meta name="description" content="Serverless Website 应用" />
7+
<meta name="keywords" content="website,serverless,无服务" />
8+
<title>Serverless - Website</title>
9+
<style lang="css">
10+
h1 {
11+
text-align: center;
12+
width: 600px;
13+
margin: 300px auto;
14+
}
15+
</style>
16+
</head>
17+
<body>
18+
<h1>Test</h1>
19+
<h2>
20+
欢迎访问静态网站
21+
<br />
22+
<a href="https://cloud.tencent.com/product/sls" target="_blank" rel="noopener noreferrer">
23+
腾讯云 Serverless
24+
</a>
25+
为您提供服务
26+
</h2>
27+
</body>
28+
</html>

src/modules/cos/index.ts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import COS, {
1010
PutBucketVersioningParams,
1111
PutBucketWebsiteParams,
1212
PutObjectResult,
13+
WebsiteConfiguration,
1314
} from 'cos-nodejs-sdk-v5';
1415
import path from 'path';
1516
import {
@@ -406,22 +407,33 @@ export default class Cos {
406407
async setWebsite(inputs: CosSetWebsiteInputs = {}) {
407408
console.log(`Setting Website for bucket ${inputs.bucket}`);
408409

410+
const websiteConfig: WebsiteConfiguration = {
411+
IndexDocument: {
412+
Suffix: inputs.code?.index ?? 'index.html',
413+
},
414+
ErrorDocument: {
415+
Key: inputs.code?.error ?? 'error.html',
416+
// FIXME: cors "Enabled" type error
417+
OriginalHttpStatus: inputs.disableErrorStatus === true ? 'Disabled' : ('Enabled' as any),
418+
},
419+
RedirectAllRequestsTo: {
420+
Protocol: inputs.protocol ?? 'http',
421+
},
422+
AutoAddressing: {
423+
Status: inputs.ignoreHtmlExt ? 'Enabled' : 'Disabled',
424+
},
425+
};
426+
427+
// 支持重定向规则配置
428+
// 参考:https://cloud.tencent.com/document/product/436/31930
429+
if (inputs.redirectRules) {
430+
websiteConfig.RoutingRules = inputs.redirectRules;
431+
}
432+
409433
const staticHostParams: PutBucketWebsiteParams = {
410434
Bucket: inputs.bucket!,
411435
Region: this.region,
412-
WebsiteConfiguration: {
413-
IndexDocument: {
414-
Suffix: inputs.code?.index ?? 'index.html',
415-
},
416-
ErrorDocument: {
417-
Key: inputs.code?.error ?? 'error.html',
418-
// FIXME: cors "Enabled" type error
419-
OriginalHttpStatus: inputs.disableErrorStatus === true ? 'Disabled' : ('Enabled' as any),
420-
},
421-
RedirectAllRequestsTo: {
422-
Protocol: inputs.protocol ?? 'htÍtp',
423-
},
424-
},
436+
WebsiteConfiguration: websiteConfig,
425437
};
426438

427439
try {
@@ -586,12 +598,12 @@ export default class Cos {
586598
await this.setPolicy(inputs);
587599
}
588600

589-
await this.setWebsite(inputs);
590-
591601
if (inputs.cors) {
592602
await this.setCors(inputs);
593603
}
594604

605+
await this.setWebsite(inputs);
606+
595607
// Build environment variables
596608
const envPath = inputs.code?.envPath || inputs.code?.root;
597609
if (inputs.env && Object.keys(inputs.env).length && envPath) {

src/modules/cos/interface.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,25 @@ export interface CosSetVersioningInputs {
106106
versioning?: string;
107107
}
108108

109+
export interface WebsiteRedirectRule {
110+
/** 重定向规则的条件配置 */
111+
Condition: {
112+
/** 指定重定向规则的错误码匹配条件,只支持配置4XX返回码,例如403或404,HttpErrorCodeReturnedEquals 与 KeyPrefixEquals 必选其一 */
113+
HttpErrorCodeReturnedEquals?: string | number;
114+
/** 指定重定向规则的对象键前缀匹配条件,HttpErrorCodeReturnedEquals 与 KeyPrefixEquals 必选其一 */
115+
KeyPrefixEquals?: 'Enabled' | 'Disabled';
116+
};
117+
/** 重定向规则的具体重定向目标配置 */
118+
Redirect: {
119+
/** 指定重定向规则的目标协议,只能设置为 https */
120+
Protocol?: 'https' | string;
121+
/** 指定重定向规则的具体重定向目标的对象键,替换方式为替换整个原始请求的对象键,ReplaceKeyWith 与 ReplaceKeyPrefixWith 必选其一 */
122+
ReplaceKeyWith?: string;
123+
/** 指定重定向规则的具体重定向目标的对象键,替换方式为替换原始请求中所匹配到的前缀部分,仅可在 Condition 为 KeyPrefixEquals 时设置,ReplaceKeyWith 与 ReplaceKeyPrefixWith 必选其一 */
124+
ReplaceKeyPrefixWith?: string;
125+
};
126+
}
127+
109128
export interface CosSetWebsiteInputs extends CosSetAclInputs, CosSetPolicyInputs, CosSetCorsInputs {
110129
bucket?: string;
111130
code?: {
@@ -120,6 +139,8 @@ export interface CosSetWebsiteInputs extends CosSetAclInputs, CosSetPolicyInputs
120139
env?: Record<string, any>;
121140
protocol?: string;
122141
disableErrorStatus?: string | boolean;
142+
ignoreHtmlExt?: boolean;
143+
redirectRules?: WebsiteRedirectRule[];
123144
}
124145

125146
export interface CosGetObjectUrlInputs {

0 commit comments

Comments
 (0)