本文介绍:
利用Azure Functions 和Cosmos DB实现一个短网址平台。
利用Functions 和Cosmos DB的免费额度,自己用可以用很久了,撸一把羊毛。
介绍的知识点有:
Functions的 自定义路由;
Cosmos DB 表存储的用法;
Functions 绑定自定义域名及SSL;
结构如下图:
1.管理员向短网址平台注册新的短网址,例如 go.abc.com/c10001,其中c10001代表某个长网址,例如 https://www.51azure.cloud/post/2021/6/7/using-javascript-azure-functions-process-telemetry-message-from-iot-hub-and-get-device-id
2. 普通用户通过 go.abc.com/c10001访问,则实际会通过浏览器访问http get 触发的 Azure functions, functions 去后台cosmos db 查询c10001对应的长地址,然后发起浏览器跳转。
代码如下:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Web;
using System.Net;
using System.Net.Http;
using Microsoft.Azure.Cosmos.Table;
namespace Company.Function
{
public static class go
{
[FunctionName("go")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route ="{key?}")] HttpRequest req,
string key,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string Url = System.Environment.GetEnvironmentVariable("Default404Url");
log.LogInformation($"Short-Url-Key:{key}");
if (!string.IsNullOrEmpty(key) && key.Length > 5)
{
string storageConnectionString = System.Environment.GetEnvironmentVariable("CosmosDBString");
// Retrieve storage information from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);
// Create a table client for interacting with the table service
CloudTableClient tableClient = storageAccount.CreateCloudTableClient(new TableClientConfiguration());
Console.WriteLine("Create a Table for the demo");
// Create a table client for interacting with the table service
CloudTable table = tableClient.GetTableReference("short-url-keys");
try
{
var partitionKey = key.Substring(0, 3);
TableOperation retrieveOperation = TableOperation.Retrieve<ShortUrlEntity>(partitionKey, key);
TableResult result = await table.ExecuteAsync(retrieveOperation);
ShortUrlEntity shortKeyEntity = result.Result as ShortUrlEntity;
if (shortKeyEntity != null)
{
log.LogInformation("\t{0}\t{1}\t{2}\t{3}", shortKeyEntity.PartitionKey, shortKeyEntity.RowKey, shortKeyEntity.Email, shortKeyEntity.Url);
Url = shortKeyEntity.Url;
}
else
{
Url = System.Environment.GetEnvironmentVariable("Default404Url");
}
//if (result.RequestCharge.HasValue)
//{
// log.LogInformation("Request Charge of Retrieve Operation: " + result.RequestCharge);
//}
}
catch (StorageException e)
{
Url = System.Environment.GetEnvironmentVariable("DefaultExceptionUrl");
}
}
else
{
Url = System.Environment.GetEnvironmentVariable("Default404Url");
}
var res = new HttpResponseMessage();
res.StatusCode = HttpStatusCode.Redirect;
res.Headers.Add("Location", Url);
return res;
}
}
}
host.json修改为如下:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensions": {
"http": {
"routePrefix": ""
}
}
}
在上述代码中,通过 Route=“{key?}” 的自定义路由,识别go.abc.com/c10001 中的 c10001,通过host.json中的 http extensions 配置,去掉默认的/api 路由。
参见:
默认情况下,所有函数路由的前缀均为 api。 还可以使用 host.json 文件中的 extensions.http.routePrefix
属性自定义或删除前缀。 以下示例通过将空字符串用于 host.json 文件中的前缀删除 api 路由前缀。
{
"extensions": {
"http": {
"routePrefix": ""
}
}
}
cosmos db中使用Table API做了如下表结构:
关于PartitionKey 和RowKey的设计仅供参考:
本例子中,将通过URL传递进来的Key作为RowKey,前三位作为PartitionKey,在表API中,PartitionKey 和Row Key共同决定了某个唯一值。
视频演示: