诚然,随着域名/链接在现代互联网中越来越被淡化,大家越来越不在意你的域名和访问的路径,但是我们仍注意到在一些场景中,例如推送通知或者发送短信,里面需要嵌入链接。我们可以看到市面上有各种各样的短链接服务,当然也有附加在这些服务上的,或者是跳转页面包含广告,或者用户无法将这个短链接和你们的业务联系在一起,这时我们就可以考虑自建一个短链接服务。
本文将使用API Gateway和DynamoDB来搭建一个短链接服务,该架构并没有使用Lambda,搭建较容易。
首先我们拆解一下我们可能需要的接口。

  1. POST,可以让我们的管理员传入原始链接,希望的短链以及标识管理员的身份
  2. GET,最终用户访问对应的短链接时,会返回给它302并且在Location Header里面包含原始链接


接下来将以最简单的方式构建这个系统,第一个部分是DyanmoDB。
1. 我们需要创建DynamoDB的表,

图片

如上图所示,我们用URL-Shortener作为表名,使用shortKey作为短链接的自定义部分,其余的保持默认。2. 我们需要创建对应的Role,Service选择API Gateway

图片

3. 简单起见,创建好这个Role后,我们为它添加一个in-line的Policy,来指定具体的DyanmoDB

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "dynamodb:GetItem",
                "dynamodb:UpdateItem"
            ],
            "Resource": "arn:aws-cn:dynamodb:cn-northwest-1:2313xxxx5197:table/URL-Shortener"
        }
    ]
}



接下来我们创建API。
1. 打开API Gateway,我们创建一个REST API,如下图,我们不需要Sample API

图片


2. 以 https://sample.com/shortKey 为例,GET请求应该落在根路径上,诚然我们也可以将POST放在根路径上,但是此处我们出于安全考虑,随机生成一个路径,并且日后也可以单独对这个路径进行进一步鉴权。

图片


3. 接下来,我们在这个新创建的路径下,创建Method

图片


集成的类型为AWS的服务,区域在宁夏,服务为DynamoDB,注意服务访问DynamoDB的方法为POST,实际的Action为UpdateItem,这里的Execution Role就是我们在IAM创建的最小权限的Role。
4. 创建后的页面如下

图片


5. 我们点击Integration Request,在最下面的Mapping Templates里面新增

图片

{  "TableName": "URL-Shortener",
  "ConditionExpression": "attribute_not_exists(shortKey)",
  "Key": {
    "shortKey": {
      "S": $input.json('$.shortKey')
    }
  },
  "ExpressionAttributeNames": {
    "#l": "originalURL",
    "#o": "owner"
  },
  "ExpressionAttributeValues": {
    ":l": {
      "S": $input.json('$.originalURL')
    },
    ":o": {
      "S":  $input.json('$.owner')
    }
  },
  "UpdateExpression": "SET #l = :l, #o = :o",
  "ReturnValues": "ALL_NEW"
}


attribute_not_exists用来判断当前shortKey是否已经使用,其他的部分则是将请求的JSON映射后存入。
6. 创建好Request后,我们点开Integration Response,也创建一个映射

图片

#set($DDBResponse = $input.path('$'))
{
    "shortKey": "$DDBResponse.Attributes.shortKey.S",
    "originalURL": "$DDBResponse.Attributes.originalURL.S",
    "owner": "$DDBResponse.Attributes.owner.S"
}


这个映射就比较简单,直接将DynamoDB的返回给客户即可。
7. 我们可以点击TEST,构造一个BODY测试一下

图片

{
  "originalURL": "https://jinshuju.net",
  "owner": "Sean",
  "shortKey": "jsj"
}


可以看到已经提交成功,此时我们也可以在DynamoDB里面确认一下。

图片


接下来我们制作用户访问对应的shortKey跳转的过程。1. 我们要在根路径下创建资源,注意此时需要资源路径为{shortKey}

图片


2. 在这个资源下创建Method,GET

图片

注意API GW调DynamoDB时为POST
3. 修改Integration Request的Mapping为下图

图片

即从Path里提取shortKey,传给DynamoDB


{
  "Key": {
    "shortKey": {
      "S": "$input.params().path.shortKey"
    }
  },
  "TableName": "URL-Shortener"
}


4. 我们需要先在Method Response中,删除200,因为这里我们要返回302,所以我们删除后添加302,同时要添加Location头

图片

5. 我们回到Integration Response,删除原来的200对应的Response,重新添加302,并且添加Mapping Template

图片
#set($DDBResponse = $input.path('$'))
#if ($DDBResponse.toString().contains("Item"))
#set($context.responseOverride.header.Location = $DDBResponse.Item.originalURL.S)
#end

6.我们测试一下

图片


后续

  1. 你可以添加自定义域名,以真正实现短链接服务
  2. 你可以在API GW前增加WAF