This topic describes the scenarios where EdgeRoutine (ER) can be used to process back-to-origin requests, operation requests and responses, subrequests, and asynchronous events.

Back-to-origin requests

  • Scenario
    In the following sample code, three HTTP request methods are used. If you want to pass the request header, request payload, and HTTP method into a back-to-origin request, we recommend that you call the Fetch API to fetch the request, as shown in Example 2 in the sample code.
    Note The Body object (body) in the following sample code represents an object of ReadableStream. The Body object is a stream that can be fetched and used only once. If you need to use the Body object multiple times, buffer it to a JavaScript object. For more information about the Stream API, see Streams API.
  • Sample code
    addEventListener('fetch', (event) => {
      event.respondWith(handleRespond(event));
    });
    
    async function handleRespond(event) {
      
      // 1. A subrequest. This operation is an independent HTTP operation. The request header and method
      // are not passed into the subrequest.
         let resp1 = await fetch("http://www.example.com");
      
      // 2. A subrequest that uses the header of the client request.
      let resp2 = await fetch("http://www.example.com", {
        body: event.request.body,
        headers: event.request.headers,
        method: event.request.method
      });
      
      // 3. Directly redirect the client request header to the origin server. The URL to be fetched is the client request URL.
      // The hostname is the host header.
      let resp3 = await fetch(event.request);
      
      // The Body object returned by the Fetch API is a stream. It cannot be fetched more than once.
      // Example:
      //    let json = await event.request.body;
      //    fetch(event.request);
      // The preceding fetch() method throws a JavaScript exception because the event.request.body stream has already been fetched.
      // You can use fetch(event.request, {body: JSON.stringify(json)});
    }

Operation requests and responses

  • Definition
    • For more information about the Request operation, see Request.
    • For more information about the Response operation, see Response.
  • Sample code
    addEventListener('fetch', (event) => {
      event.respondWith(handleResponse(event));
    });
    
    async function handleResponse(event) {
      // 1.The properties or methods that correspond to the Request object.
      {
        let request = event.request;
        
        // The request method.
        let method = request.method;
        // The request path.
        let path = request.path;
        // The request URL.
        let url = request.url;
        // The request header.
        let headers = request.headers;
        // The request payload. The body is a ReadableStream object, not a String or ArrayBuffer object.
        let body = request.body;
      }
      
      // 2. The properties and methods that correspond to the Response object.
      {
        let response = new Response("Hello World", {
          status: 200,
          statusText: "Perfect",
          headers: [[
            "X-Special-Header1": "value1",
            "X-Where-Am-I": "edge"
          ]]
        });
        
        // The status code of the response.
        let status = response.status;
        
        // The status message of the response.
        let statusText = response.statusText;
        
        // The response header.
        let header = response.headers;
        
        // Indicates whether the response is a 3xx redirect.
        let is3XX = response.redirected;
        
        // The response body.
        let body = response.body;
      }
      
      // 3. How the Body mixin is used and the properties of the Body mixin. The Body mixin applies to both the Request and Response objects.
      {
        let response = new Response("Hello World");
        
        // Treats the body as a String object and encodes it in UTF-8.
        // let string = await response.text();
        
        // Treats the body as an ArrayBuffer, which is a binary object. The encoding method is unknown.
        // let binary = await response.arrayBuffer();
        
        // Treats the body as a JSON object and encodes it in UTF-8.
        // let json = await response.json();
        
        // Treats the body as form data.
        // The response header must contain
        //   (1) content-type: application/x-www-urlform-encoded
        // or
        //   (2) content-type: multipart/form-data
        // let formData = await response.formData();
        
        // The preceding method fetches all information in the stream. The stream then becomes unusable and cannot be locked to any reader.
      }
      return "done";
    }

Subrequests

  • Definition

    The core of a subrequest is the Fetch API. It is a non-asynchronous API that returns a Promise object.

  • Sample code
    addEventListener('fetch', (event) => {
      event.respondWith(handleResponse(event));
    });
    
    async function handleResponse(event) {
      // 1. Create a fetch request.
      let resp1 = await fetch("http://www.example.com");
      
      // 2. Configure special request headers.
      {
        let hdr = new Headers({
          "X-Cache" : "Hit",
          "User-Agent" : "Hello from EdgeRoutine"
        });
        let resp2 = await fetch("http://www.example.com", {headers: hdr});
      }
      
      // 3.post/delete/head/put
      {
        let resp3 = await fetch("http://www.example.com", {method: "POST", body: "Hey Jude"});
      }
      
      // 4. Send the request body.
      // 4.1 A string.
      // 4.2 ArrayBuffer and Uint8Array.
      // 4.3 A stream.
      {
        let resp4 = await fetch("http://www.example.com", {method: "POST", body: "data"});
        let resp5 = await fetch("http://www.example.com", {method: "POST", body: new Uint8Array(10)});
        let upstream = await fetch("http://www.taobao.com");
        let resp6 = await fetch("http://www.example.com", {method: "POST", body: upstream.body});
      }
      
      // 5. Use the Request object to fetch data.
      {
        let req = new Request("http://www.taobao.com", {method: "POST", body: "data"});
        let resp7 = await fetch(req);
      }
      
      // 6. By default, a fetch request does not perform a 3xx redirect.
      {
        // Automatically redirects to another URL. For example, requests sent to the Tmall site are redirected to the corresponding HTTPS URL.
        let resp = await fetch("http://www.tmall.com", {redirect: "follow"});
        
        // Fetches the URLs of all requests.
        let urlList = resp.urlList;
        for (const url of urlList) {
                console.log(url);
        }
      }
      
      return "done";
    }

Asynchronous events

  • Definition

    After the Response object is sent by EdgeRoutine (ER), the context of the request is cleared. Pending asynchronous requests are then canceled. This event is known as an asynchronous event. For more information about the Response object, see ExtendableEvent.waitUntil().

  • Sample code
    addEventListener('fetch', (event) => {
      event.respondWith(handleResponse(event));
    });
    
    async function handleResponse(event) {
        let resp = fetch("http://www.taobao.com");
      
      // 1. To ensure that the preceding fetch operation can be completed, you must use the event.waitUntil method or the await keyword.
      // Synchronize asynchronous requests.
      event.waitUntil(resp);
      
      // 2. Directly respond to the client request. The preceding fetch request can be processed asynchronously while the response is
      // returned to the client.
      return "done";
    }