前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【玩转 EdgeOne】使用EdgeOne边缘函数搭建域名注册查询API

【玩转 EdgeOne】使用EdgeOne边缘函数搭建域名注册查询API

原创
作者头像
HuoYun
发布2023-10-31 22:51:48
2140
发布2023-10-31 22:51:48
举报
文章被收录于专栏:部署实践部署实践

使用EdgeOne边缘函数搭建域名注册查询API

前言

突然心血来潮,想注册个4位的.cn域名,但一个个查显然是不可能的事情,于是萌生了写一个查询域名是否已注册的API的想法。

恰巧上周四活动抢了个EdgeOne套餐,正好拿来试试他的边缘函数。

原理

用户访问API,EdgeOne根据规则路由到边缘函数。

边缘函数获取用户需要查询的域名,并请求腾讯云域名注册的API查询域名是否可用。

最后解析并返回查询结果。

准备工作

● 一个EdgeOne套餐,可以点击这里购买。或者点击这里参加最新的活动,一年仅需45元

● 账号的API凭证,可以点击这里获取

开发计划

调用方式

使用GET请求,通过GET参数携带待查询域名

代码语言:txt
复制
https://api.com/?domain=[待查询域名]

返回数据结构

API对接的是腾讯云的域名查询接口,根据文档可知,接口返回如下数据:

因为API的用途是查询域名是否可注册,所以只需要其中部分返回参数即可。

域名不可注册分为两种,一是已经被注册了,二是有敏感词。

当一个域名未被注册但是存在敏感词也会被标记为 不可注册。

所以需要保留敏感词字段,用来给用户做二次的判断。

正常返回

代码语言:txt
复制
{
  "code": 0,
  "DomainName": "域名",
  "Available": false,
  "BlackWord": false,
  "Reason": "不可注册说明"
}

报错返回

代码语言:txt
复制
{
  "code": 1,
  "Message": "报错内容",
  "ErrorCode": "报错代码"
}

代码编写

代码语言:txt
复制
// 将字符串编码为ArrayBuffer
function stringToArrayBuffer(str) {
    const encoder = new TextEncoder();
    return encoder.encode(str);
  }

  // 将ArrayBuffer转换为十六进制字符串
  function arrayBufferToHexString(arrayBuffer) {
    const byteArray = new Uint8Array(arrayBuffer);
    const hexCodes = [...byteArray].map(value => value.toString(16).padStart(2, '0'));
    return hexCodes.join('');
  }

  async function hmacSHA256(key, data) {
    const importedKey = await crypto.subtle.importKey(
      'raw',
      key,
      { name: 'HMAC', hash: 'SHA-256' },
      false,
      ['sign']
    );

    const msgBuffer = stringToArrayBuffer(data);
    const signatureBuffer = await crypto.subtle.sign('HMAC', importedKey, msgBuffer);

    return signatureBuffer;
  }

  function uint8ArrayToHex(array) {
    return Array.from(array).map(byte => byte.toString(16).padStart(2, '0')).join('');
  }

  // 签名算法
  async function qcloud_v3_post(SecretId,SecretKey,Service,bodyString,headersOper) {
    const HTTPRequestMethod = "POST"
    const CanonicalURI = "/"
    const CanonicalQueryString = ""

    // 将 JSON 对象中的键按 ASCII 升序进行排序
    let sortedheadersOper = Object.keys(headersOper).filter(key => (key.toLowerCase() !== "x-tc-version")).sort();
    // 遍历排序后的键并拼接
    let SignedHeaders = sortedheadersOper.map(key => key.toLowerCase()).join(";");
    let CanonicalHeaders = sortedheadersOper.map(key => key.toLowerCase() + ":" + headersOper[key].toLowerCase()).join("\n");
    CanonicalHeaders = CanonicalHeaders + "\n"

    let HashedRequestPayload = await sha256(bodyString)

    const CanonicalRequest =
      HTTPRequestMethod + '\n' +
      CanonicalURI + '\n' +
      CanonicalQueryString + '\n' +
      CanonicalHeaders + '\n' +
      SignedHeaders + '\n' +
      HashedRequestPayload

    const currentDate = new Date();
    const year = currentDate.getUTCFullYear();
    const month = (currentDate.getUTCMonth() + 1).toString().padStart(2, '0');
    const day = currentDate.getUTCDate().toString().padStart(2, '0');
    const formattedDate = `${year}-${month}-${day}`;


    const Algorithm = "TC3-HMAC-SHA256"
    // 获取当前秒级时间戳
    const RequestTimestamp = Math.floor(Date.now() / 1000).toString();
    // const RequestTimestamp = "1688025007"
    const CredentialScope = formattedDate + "/" + Service + "/tc3_request"
    const HashedCanonicalRequest = await sha256(CanonicalRequest)

    const StringToSign =
      Algorithm + '\n' +
      RequestTimestamp + '\n' +
      CredentialScope + '\n' +
      HashedCanonicalRequest

    const SecretDate = await hmacSHA256(new Uint8Array([...stringToArrayBuffer("TC3"), ...new Uint8Array(stringToArrayBuffer(SecretKey))]), formattedDate);
    const SecretService = await hmacSHA256(SecretDate, Service);
    const SecretSigning = await hmacSHA256(SecretService, "tc3_request");

    const Signature = arrayBufferToHexString(await hmacSHA256(SecretSigning, StringToSign));

    const Authorization =
      Algorithm + ' ' +
      'Credential=' + SecretId + '/' + CredentialScope + ', ' +
      'SignedHeaders=' + SignedHeaders + ', ' +
      'Signature=' + Signature

      headersOper["X-TC-Timestamp"] = RequestTimestamp;
      headersOper["Authorization"] = Authorization;

      return headersOper
  }

  // sha256 签名摘要
  async function sha256(message) {
    const msgBuffer = new TextEncoder().encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);


    return uint8ArrayToHex(new Uint8Array(hashBuffer));
  }

  // 密钥填写位置
  const SecretId = "";
  const SecretKey = "";
  const Service = "domain";

  async function handleRequest(request) {

    const url = new URL(request.url)
    const params = url.searchParams
    const checkdomain = params.get("domain");

    let checkRetrunData = {};

    if(checkdomain === null){
      checkRetrunData["code"] = 1;
      checkRetrunData["Message"] = "域名参数为空";
      checkRetrunData["ErrorCode"] = "DomainIsNULL";
      return new Response(JSON.stringify(checkRetrunData, null, 2), { 
        headers: { 'Content-Type': 'application/json',
        'Access-Control-Allow-Headers': 'Content-Type',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Max-Age': '86400',
        'Access-Control-Allow-Origin': '*' },
        status: 200 
      })
    }

    const headersPending = {
      'Host': 'domain.tencentcloudapi.com',
      'Content-Type': 'application/json',
      'X-TC-Action': 'CheckDomain',
      'X-TC-Version': '2018-08-08',
      'X-TC-Region': 'ap-guangzhou',
    };


    const apiBodyJson = {
      "DomainName": checkdomain
    }

    const bodyString = JSON.stringify(apiBodyJson)

    const headers = await qcloud_v3_post(SecretId,SecretKey,Service,bodyString,headersPending)

    const apiurl = 'https://domain.tencentcloudapi.com/';

  let qcloud_api_data;
  await fetch(apiurl, {
    method: 'POST',
    headers: headers,
    body: bodyString
  })
  .then(response => response.json())
  .then(data => qcloud_api_data = data)
  .catch(error => qcloud_api_data = error);

  if(qcloud_api_data["Response"]["Error"] === undefined){
    checkRetrunData["code"] = 0;
    checkRetrunData["DomainName"] = qcloud_api_data["Response"]["DomainName"];
    checkRetrunData["Available"] = qcloud_api_data["Response"]["Available"];
    checkRetrunData["BlackWord"] = qcloud_api_data["Response"]["BlackWord"];
    checkRetrunData["Reason"] = qcloud_api_data["Response"]["Reason"];
  }else{
    checkRetrunData["code"] = 1;
    checkRetrunData["Message"] = qcloud_api_data["Response"]["Error"]["Message"];
    checkRetrunData["ErrorCode"] = qcloud_api_data["Response"]["Error"]["Code"];
  }

    return new Response(JSON.stringify(checkRetrunData, null, 2), { 
        headers: { 'Content-Type': 'application/json',
        'Access-Control-Allow-Headers': 'Content-Type',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Max-Age': '86400',
        'Access-Control-Allow-Origin': '*' },
        status: 200 
      })
  }

  addEventListener('fetch', (event) => {
    if (event.request.method === 'OPTIONS') {
      event.respondWith(handleOptions(event.request))
    } else {
      event.respondWith(handleRequest(event.request))
    }
  });

使用体验

相较于云函数的固定地域,EdgeOne的边缘函数部署在各边缘节点,延迟更低。

更重要的是,边缘函数目前免费使用,用来部署一些小应用十分不错,节省了服务器资源也提升了用户体验。

唯一的缺点是没有调试功能,编写时出错排查起来会困难些,不过作为一款新产品,边缘函数也处于公测当中,日后应该会加上调试功能。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用EdgeOne边缘函数搭建域名注册查询API
  • 前言
  • 原理
  • 准备工作
  • 开发计划
    • 调用方式
      • 返回数据结构
        • 正常返回
        • 报错返回
    • 代码编写
    • 使用体验
    相关产品与服务
    内容分发网络 CDN
    内容分发网络(Content Delivery Network,CDN)通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档