All Products
Search
Document Center

CDN:EdgeScript use case examples

Last Updated:Apr 01, 2026

EdgeScript lets you write custom logic that runs on Alibaba Cloud CDN points of presence (POPs) — without touching your origin server. Use EdgeScript to control authentication, headers, URL rewrites, cache time-to-live (TTL) values, throttling, and access control at the edge.

The following table summarizes the scenarios covered in this document:

ScenarioWhat it does
AuthenticationValidates URL signatures for .ts requests; returns HTTP 403 on failure
Request and response headersSets Content-Disposition to trigger a named file download
Rewrites and redirectsRewrites URIs, changes file extensions, normalizes case, adds prefixes, performs 302 redirects
Cache controlSets TTL values per URL pattern or HTTP status code
ThrottlingLimits transfer rate based on URL parameters
Region and ISP access controlBlocks requests from specific regions or Internet service providers (ISPs)

Customize authentication rules

EdgeScript authentication can cover a range of scenarios, including URL signature validation (hotlink protection), IP allowlist enforcement, and User-Agent filtering. The script below implements URL signature–based hotlink protection for .ts requests.

The script enforces three rules in sequence:

  1. The request must include both the t (expiration time) and key parameters — otherwise the POP returns HTTP 403.

  2. The t parameter must be a valid number and must not be earlier than the current POP time — otherwise the POP returns HTTP 403.

  3. The MD5 hash of (private key + path + filename.extension) must match the digest segment in the URL — otherwise the POP returns HTTP 403.

Request URL format: /path/digest/?.ts?key=&t=

# Only apply authentication to .ts requests
if eq(substr($uri, -3, -1), '.ts') {

  # Rule 1: Reject if t or key parameters are missing
  if or(not($arg_t), not($arg_key)) {
    add_rsp_header('X-AUTH-MSG', 'auth failed - missing necessary arg')
    exit(403)
  }

  # Rule 2: Reject if t is not a valid number
  t = tonumber($arg_t)
  if not(t) {
    add_rsp_header('X-AUTH-MSG', 'auth failed - invalid time')
    exit(403)
  }

  # Reject if the URL has expired.
  # t is compared against the POP's local clock, not the client clock.
  # If the client clock differs significantly from the POP clock, valid
  # requests may be rejected. Add a time buffer when generating signed URLs.
  if gt(now(), t) {
    add_rsp_header('X-AUTH-MSG', 'auth failed - expired url')
    exit(403)
  }

  # Rule 3: Extract path segments using a regular expression
  pcs = capture_re($request_uri,'^/([^/]+)/([^/]+)/([^?]+)%?(.*)')
  sec1 = get(pcs, 1)
  sec2 = get(pcs, 2)
  sec3 = get(pcs, 3)

  if or(not(sec1), not(sec2), not(sec3)) {
    add_rsp_header('X-AUTH-MSG', 'auth failed - malformed url')
    exit(403)
  }

  # Compute MD5(private_key + path + filename) and compare with digest
  key = 'b98d643a-9170-4937-8524-6c33514bbc23'
  signstr = concat(key, sec1, sec3)
  digest = md5(signstr)

  if ne(digest, sec2) {
    add_rsp_header('X-AUTH-DEBUG', concat('signstr: ', signstr))
    add_rsp_header('X-AUTH-MSG', 'auth failed - invalid digest')
    exit(403)
  }
}

Customize request headers and response headers

The script below sets the Content-Disposition response header to trigger an automatic file download with a custom filename. When the request includes a filename URL parameter, the browser saves the response body under that name. If the parameter is absent, the browser uses the default filename.

Expected response header:

Content-Disposition: attachment;filename="monitor.apk"
Note

The filename value is wrapped in double quotation marks. tochar(34) converts ASCII code 34 to the " character, because quotation marks cannot be embedded directly in the string.

if $arg_filename {
  hn = 'Content-Disposition'
  hv = concat('attachment;filename=', tochar(34), $arg_filename, tochar(34))
  add_rsp_header(hn, hv)
}

Customize rewrites and redirects

Rewrite a URI

Rewrite /hello to /index.html. The back-to-origin request uses /index.html and all URL parameters are preserved.

if match_re($uri, '^/hello$') {
    rewrite('/index.html', 'break')
}

Rewrite a file extension

Replace the file extension in the URI with the value of the type URL parameter. For example, /1.txt?type=mp4 becomes /1.mp4?type=mp4 before the request is forwarded to the origin. The retrieved content is then cached on CDN POPs.

if and(match_re($uri, '^/1.txt$'), $arg_type) {
    rewrite(concat('/1.', $arg_type), 'break')
}

Convert a file extension to lowercase

Normalize the file extension to lowercase. For example, /image/Photo.JPG becomes /image/Photo.jpg.

pcs = capture_re($uri, '^(.+%.)([^.]+)')
section = get(pcs, 1)
postfix = get(pcs, 2)

if and(section, postfix) {
    rewrite(concat(section, lower(postfix)), 'break')
}

Add a URI prefix

Rewrite any URI matching ^/nn_live/(.*) by prepending /3rd. For example, /nn_live/stream1 becomes /3rd/nn_live/stream1.

pcs = capture_re($uri, '^/nn_live/(.*)')
sec = get(pcs, 1)

if sec {
    dst = concat('/3rd/nn_live/', sec)
    rewrite(dst, 'break')
}

Perform a 302 redirect

Redirect requests to the / root path to /app/movie/pages/index/index.html.

if eq($uri, '/') {
    rewrite('/app/movie/pages/index/index.html', 'redirect')
}

Redirect to an HTTPS URL

Redirect requests to the root path — whether arriving over HTTP or HTTPS — to a specific HTTPS URL. Replace https://demo.aliyundoc.com/index.html with your target URL.

if eq($uri, '/') {
    rewrite('https://demo.aliyundoc.com/index.html', 'redirect')
}

Customize cache control

The script below sets the TTL for cached resources based on URL patterns and HTTP status codes.

# For /image URLs: cache 301 responses for 10 s, 302 responses for 5 s
if match_re($uri, '^/image') {
    set_cache_ttl('code', '301=10,302=5')
}

# For .mp4 files: TTL = 5 s
if eq(substr($uri, -4, -1), '.mp4') {
    set_cache_ttl('path', 5)
}

# For /201801/mp4/ paths: TTL = 50 s
if match_re($uri, '^/201801/mp4/') {
    set_cache_ttl('path', 50)
}

# For /201802/flv/ paths: TTL = 10 s
if match_re($uri, '^/201802/flv/') {
    set_cache_ttl('path', 10)
}

set_cache_ttl accepts two modes:

  • 'code' — sets TTL per HTTP status code, using the format '<code>=<seconds>[,<code>=<seconds>]'

  • 'path' — sets TTL in seconds for all responses matching the URI pattern

Customize throttling policies

The script below reads the sp (speed limit) and unit parameters from the request URL and applies throttling using limit_rate(). Both parameters must be present for throttling to take effect.

ParameterDescriptionValid values
spMaximum transfer rate before throttling takes effectPositive integer
unitUnit of the ratek (KB) or m (MB)
if and($arg_sp, $arg_unit) {

  # Validate that sp is a positive integer
  sp = tonumber($arg_sp)
  if not(sp) {
    add_rsp_header('X-LIMIT-DEBUG', 'invalid sp')
    return false
  }

  # Validate that unit is k (KB) or m (MB)
  if and(ne($arg_unit, 'k'), ne($arg_unit, 'm')) {
    add_rsp_header('X-LIMIT-DEBUG', 'invalid unit')
    return false
  }

  add_rsp_header('X-LIMIT-DEBUG', concat('set on: ', sp, $arg_unit))
  limit_rate(sp, $arg_unit)
  return true
}

Region- and ISP-based access control

The script below restricts access based on the region and Internet service provider (ISP) of the client IP address. Requests from any region or ISP not in the allowlist are blocked with HTTP 403.

client_region() returns the region code of the client IP. client_isp() returns the ISP code. For the full list of region and ISP codes, see Request logic functions.

# Block requests from regions not in the allowlist
ip_region_id = client_region()
if not(match_re(ip_region_id, '440000|370000')) {
    add_rsp_header('X-REGION-BLOCK-DEBUG', concat('hit ip_region_id:', ip_region_id))
    exit(403)
}

# Block requests from ISPs not in the allowlist
ip_isp_id = client_isp()
if not(match_re(ip_isp_id, '100017|100025')) {
    add_rsp_header('X-REGION-BLOCK-DEBUG', concat('hit ip_isp_id:', ip_isp_id))
    exit(403)
}

Replace '440000|370000' and '100017|100025' with the region and ISP codes that match your access policy.