All Products
Search
Document Center

Edge Security Acceleration:Edge function FAQ

Last Updated:Oct 15, 2026

Cannot get the real client IP

Symptom

After an edge function processes a request, the IP address retrieved from the ali-real-client-ip header is always an internal IP address, not the real client IP.

Cause

When you use fetch mode, the edge function acts as an intermediate proxy that sends requests to the origin. The origin receives requests from the edge runtime, causing the ali-real-client-ip header to return the edge node's internal IP address instead of the real client IP.

Solution

Enable Bypass Mode to prevent the edge function from processing requests. This ensures the original client IP is preserved. For detailed instructions, see the bypass mode section in Domain Configuration.

The following table describes the key differences between fetch mode and bypass mode.

Mode

Real IP

Use cases

fetch mode

Returns an internal IP address

Scenarios where the edge function needs to modify response content, such as compression or rewriting.

bypass mode

Returns the real client IP

Lightweight scenarios such as authentication and logging.

To implement this logic in your edge function code, change the entry point from async fetch(request) to async bypass(request). The ResponseBypass object, a built-in utility in the ESA edge runtime, controls whether a request bypasses function processing:

// Entry function for bypass mode
async bypass(request) {
  // Execute pre-processing logic, such as authentication.
  const isAuthPassed = true; // Replace with your actual authentication logic.

  if (isAuthPassed) {
    // Authentication succeeded. Return true to bypass function processing.
    return new ResponseBypass(true);
  } else {
    // Authentication failed. Return false and specify a failure status code.
    return new ResponseBypass(false, { status: 403 });
  }
}
Note
  • When bypass mode is enabled, the edge function does not receive the request body. If you need to read the request body, for example from a POST request, use fetch mode instead.

  • Bypass mode is for lightweight tasks like authentication and logging, not for modifying the response with compression or rewriting, and it does not consume CPU time for response processing.

Verification

After enabling bypass mode, verify that the ali-real-client-ip header returns the real client IP using one of the following methods:

  • Use the curl command to check the response headers:

    curl -I https://your-domain.com

    Check the ali-real-client-ip value in the response headers. It must be the client's public IP, not an internal IP.

  • In the browser developer tools, open the Network panel and check the ali-real-client-ip value in the response headers.

Can the variable key be modified?

No, it cannot be modified. The key is not editable once created. If you need to make changes, please delete it and add a new one.

Why do I read undefined?

If the current version is not bound to the variable, or the key is configured only in the other environment, the code returns undefined and does not throw an exception. Check whether the key is configured in the target environment, and whether you redeployed the version after you configured the key.

Are variables bound to versions?

Yes. Function variables are bound together with a version. If you change variables in the console without releasing a new version, the running version does not detect the change.

What if an encrypted variable fails to be decrypted?

If the value of an encrypted key cannot be decrypted, the edge function returns a 599 error. Check whether the variable value was encrypted and written correctly.

How do I switch to bypass mode by modifying my code?

Take Type A URL signing as an example:

  • Change the entry function from async fetch() to async bypass().

  • The function must return a value constructed with new ResponseBypass(), which takes two parameters:

    • The first parameter is a boolean (true or false) indicating whether authentication succeeded.

    • If authentication fails (false), you can pass a second status parameter to specify the status code to return to the client.

Example code for original Type A signing

import { createHash } from "node:crypto";

async function handleRequest(request) {
  const url = new URL(request.url);
  const path = url.pathname;
  const delta = 3600;

  const authKeyTypeA = url.searchParams.get('auth_key');

  const privateKey = 'your_secret_key'
  const currentTimestamp = Math.floor(Date.now() / 1000);

  if (!authKeyTypeA) {
    // In an authentication failure scenario, the edge node returns a 403 error to the client by default.
    return new Response('Unauthorized', { 
      status: 401,
    });
  }

  const [timestamp, rand, uid, signature] = authKeyTypeA.split('-');

  if (currentTimestamp > parseInt(timestamp)+ delta) {
    // In an authentication failure scenario, the edge node returns a 403 error to the client by default.
    return new Response('Link expired', {
      status: 403,
    });
  }

  const signString = [path, timestamp, rand, uid, privateKey].join('-');

  const md5 = createHash('md5').update(signString).digest('hex');

  if (md5 !== signature) {
  
    return new Response('Unauthorized', {
      status: 401
    });
  }

  // If the resource is on another domain, fetch it and return the response.
  // const yourUrl = `https://your-dcdn-domain.com${path}${url.search}`
  // const cdnResponse = await fetch(yourUrl, request)
  // return new Response(cdnResponse.body, cdnResponse)

  // In most cases, fetching from the origin is sufficient.
  return fetch(request.url)
}

export default {
  async fetch(request) {
    return handleRequest(request)
  }
}

Example code for Type A signing with bypass mode

import { createHash } from "node:crypto";

async function handleRequest(request) {
  const url = new URL(request.url);
  const path = url.pathname;
  const delta = 3600;

  const authKeyTypeA = url.searchParams.get("auth_key");

  const privateKey = "your_secret_key";
  const currentTimestamp = Math.floor(Date.now() / 1000);

  if (!authKeyTypeA) {
    // Authentication failed. If you pass false, the edge node returns a 403 error to the client by default.
    return new ResponseBypass(false, {
      status: 401,
    });
  }

  const [timestamp, rand, uid, signature] = authKeyTypeA.split("-");

  if (currentTimestamp > parseInt(timestamp) + delta) {
    // Authentication failed. If you pass false, the edge node returns a 403 error to the client by default.
    return new ResponseBypass(false, {
      status: 403,
    });
  }

  const signString = [path, timestamp, rand, uid, privateKey].join("-");

  const md5 = createHash("md5").update(signString).digest("hex");

  if (md5 !== signature) {
    // Authentication failed. If you pass false, the edge node returns a 403 error to the client by default.
    return new ResponseBypass(false, {
      status: 401,
    });
  }

  // Authentication succeeded. If you pass true, the request proceeds to the origin, and the response is no longer processed by this function.
  const resSuccess = new ResponseBypass(true);
  return resSuccess;
}

export default {
  async bypass(request) {
    return handleRequest(request);
  },
};

How do I change a domain name binding?

If your current domains and routes no longer meet your needs, edit or delete them.

  1. Log on to the ESA console, and in the navigation pane on the left, choose Edge Computing and AI > Functions & Pages. Click the target Functions & Pages instance.

  2. Click the Domains tab.

  3. On the Domain Names tab you can delete a bound domain name and then add it again. For a bound route, you can edit it, or delete it and add it again.

How do I bind Functions and Pages directly to a root domain?

To bind Functions and Pages directly to a root domain such as example.com, use one of the following methods:

  • Custom Domains: Select Add Domain Name and enter @.example.com as the domain name.

  • Routes: Select Add Route. For the site, use Select Website to select example.com. For Route Mode, select Simple Mode and leave Route Prefix blank.

Invalid status code

Error message

HttpBody.constructor: invalid status code

Cause

The status codes 596, 597, 598, and 599 are reserved for internal use by the edge runtime. Do not return these status codes in your function.

No available proxy address

Error message

unhandled error(13485,13477)@: Error: io error@: no available fetch proxy address now\nstacktrace:\nN/A\n

Cause 1

The URL passed to cache.put starts with https. The cache API does not support https. Change https to http.

Cause 2

A fetch request targets a domain not managed by ESA, but the cdnProxy:true option is set. To fix this, either add the domain to your ESA service or remove the cdnProxy:true configuration.

Broken connection

Error message

Error: unhandled error(13486,13505)@: Broken connection, unexpected EOF

Cause

The origin closed the connection while the edge function was receiving data from it.