百度智能云

All Product Document

          CDN

          EJS Rule Configuration Method

          Overview

          EdgeJS provides you with programmable custom edge configuration services. Baidu took the lead to support nginx to extend js object, and support to execute JavaScript code written by yourself at edge server. High performance, low delay and simple configuration help you rapidly customize business to greatly reduce business realization cost.

          Feature

          • VM bound with request lifecycle.
          • Non-blocked execution process.
          • Realize based on ECMAScript standard.
          • Tightly integrated with the request processing stage.

          Syntax

          JavaScript Global Feature

          Request object r of HTTP

          Sub-member of the request object r Description
          r.uri Request url, which is writable
          r.args{} The request parameter object is writable.
          r.headersIn{} Request header object, writable.
          Foo request header can be accessed by r.headersIn.foo or r.headersIn['Foo'].
          As for the headers occurring multiple times, such as “Cookie” or “X-Forwarded-For”, the headersIn only returns the first one.
          If you want to get all the cookie headers, you need to use r.variables.http_cookie.
          Use r.variables["cookie_name"] to access the cookie of the name.
          r.headersOut{} The response header object is writable.
          Foo response header can be accessed by r.headersOut.foo or r.headersOut ['Foo'].
          r.respHeader(callback) Method to register response header processing callback The r.headersOut and r.scriptatus passed at the back end can be modified in the callback.
          r.httpVersion The version of http protocol, 0.9/1.0/1.1, is read-only.
          r.method The http methods, like GET/HEAD/PUT/POST, etc. are read-only.
          r.remoteAddress Client address, which is read-only.
          r.variables{} The object of nginx variable is partially writable.
          Get complete request header to use r.variables.http_cookie (read only).
          Use r.variables['limit_rate'] to set speed limit.

          Response handling method Description
          r.status Set the response code, which is writable.
          r.sendHeader() Send http response header to the client.
          Set the status code by r.status; set response header through r.headersOut{}, use r.sendHeader() to send response header, and send response body through r.send(string) if there is response body.
          In case of no response body, call r.finish() to finish.
          r.send(string) Send part of the response string to client, and call r.finish() to finish after the sending completes.
          r.finish() Complete the request processing, the response completes.
          r.return(status[, string]) The status of the assigned response code, send the whole response string to the client simultaneously, and no r.send(string) sending response can be called successively.
          Can be used for redirecting, status is assigned as 301, 302, 303, 307 or 308, and redirect URL as the second parameter.
          Note This method does not end the running of the js code. If you want to end the script, you have to use the return global keyword to exit the js code after r.return.

          Processing of child request Description
          r.parent Parent request object, read-only.
          r.responseBody Child request response body, which is read-only.
          r.subrequest(uri[, options[, callback]]) Create a sub-request, and assign uri, options and callback.
          The child request shares the request header of the parent request. options: If it is a string, it indicates the parameter of a child request; otherwise, it shall be an object, having the following keys:
          args: string,The request parameter defaults to null.
          body: string,Request body, the same as the parent request body by default.
          method: string,For the request method, it defaults to GET
          callback: The child request completes the callback, with the form of function done (res) {}, and res is the responding object of the child request, with the same methods and attribute as the parent request.

          Crypto

          Provide password type function support, and use through require ('crypto') return.

          Hash Description
          crypto.createHash(algorithm) Create and return hash object, and use designated algorithm to generate hash abstract.
          The algorithm supports md5, sha1 and sha256.
          hash.update(data) Use designated data to update hash computing results.
          hash.digest([encoding]) Compute the hash abstract of all data passed through hash.update()
          encoding supports hex, base64 and base64url, and the default is byte string if it is not specified.

          HMAC Description
          crypto.createHmac(algorithm, secret key) Create and return HMAC object, and use designated algorithm and secret key.
          The algorithm supports md5, sha1 and sha256.
          hmac.update(data) Use designated data to update HMAC computing results.
          hmac.digest([encoding]) For all data passed through hmac.update(), compute its hmac abstract
          encoding supports hex, base64 and base64url, and it defaults to be byte string if not specified.

          baidu_utils database

          function ipInCidr(ipv4, cidrs)

          Parameter: 
              The ipv4 is an ipv4 address in dotted decimal, such as '192.168.2.100' 
              The cidrs is the CIDR address list, such as ['192.168.1.1/32','192.168.2.1/24'] 
           
          Use case: 
              if (baidu_utils.ipInCidr('192.168.2.100', ['192.168.1.1/32','192.168.2.1/24'])) { 
                  r.return(403); 
              } 

          Base64

          encode

          '1234'.toBytes().toString('base64');
          '1234'.toBytes().toString('base64url');
          require('crypto').createHash('sha1').update('A').update('B').digest('base64');
          require('crypto').createHmac('sha1', 'key').update('A').update('B').digest('base64url');

          decode

          String.bytesFrom('MTIzNA==', 'base64');
          String.bytesFrom('MTIzNA', 'base64url');

          Scenario Example

          Rewrite the file name

          Use request parameter filename to name the downloaded file

          r.headersOut['Content-Disposition']='attachment;filename=' + '\"' + r.args['filename'] + '\"'; 

          Cross-domain access

          Use the request head Origin, and assign a value to cross-domain response head Access-Control-Allow-Origin

          r.headersOut['Access-Control-Allow-Origin']=r.headersIn['Origin']; 

          Redirection

          r.return(302, '/a'); 

          Access control

          IP blacklist/whitelist

          if (baidu_utils.ipInCidr(r.remoteAddress, ['192.168.1.1/32','192.168.2.1/24'])) { r.return(403); } 

          Referer blacklist and whitelist

          var refers = ['http://*.baidu.com.cn/*','http://*.baidu.com/*']; 
          var i = 0; 
          for (; i < refers.length; i += 1) { 
              if (baidu_utils.matchWildcard(r.headersIn['referer'], refers[i])) { 
                  r.return(403); 
                  return; 
              } 
          } 

          UA blacklist/whitelist

          var uas = ['curl','AppleWebKit']; 
          var i = 0; 
          var ua = r.headersIn['User-Agent']; 
          for (; i < uas.length; i += 1) { 
              if (ua.includes(uas[i])) { 
                  r.return(403); 
                  return; 
              } 
          } 

          Rate limit

          r.variables['limit_rate'] = '1k'; 

          Authentication

          Take [Type-B hotlink Protection](https://cloud.baidu.com/doc/CDN/s/ujwvyeo0t#b%E7%B1%BB%E9%89%B4%E6%9D%83%E6%96% B9%E5%BC%8F) as an example

          var part = r.uri.substr(1).split('/'); 
          if (part.length < 3) { 
              r.return(403); 
              return; 
          } 
           
          var date_in_uri = part[0]; 
          var d = new Date(''); 
          d.setFullYear(date_in_uri.substring(0, 4)); 
          d.setMonth(date_in_uri.substring(4, 6) - 1); //the month (0-11) in the specified date 
          d.setDate(date_in_uri.substring(6, 8)); 
          d.setHours(date_in_uri.substring(8, 10)); 
          d.setMinutes(date_in_uri.substring(10)); 
          var time = d.getTime(); 
          var timeout = 1000000000000; // not overdue 
          if (time + timeout < Date.now()) { 
              r.return(403); 
              return; 
          } 
           
          var md5_in_uri = part.splice(1,1)[0]; 
          var md5_str = 'bdcloud666' + part.join('/'); 
          var md5 = require('crypto').createHash('md5').update(md5_str).digest('hex'); 
          if (md5_in_uri != md5) { 
              r.return(403); 
              return; 
          } 

          Sub-request

          The child request js returns when calling back the function of done, and the defined variables other than the function done called back can also be seen in the function done; for example, the code after the variables test and r.subrequest is executed before the function done, and the final response head x-test is valued OK.

          var test = 'test'; 
           
          function done(res) { 
              for (var key in res.headersOut) { 
                  r.headersOut[key] = res.headersOut[key]; 
              } 
           
              r.headersOut['x-test'] = test; 
          } 
           
          r.subrequest('/foo', r.variables.args, done); 
          r.subrequest('/bar', r.variables.args, done); 
           
          test = 'OK'; 

          Modification requesturi

          r.uri = '/test'; 

          Modification requestargs

          r.args['test1'] = 'test'; 
          if (r.args['test1'] == 'test') { /* use first one if duplicate */ 
              delete r.args['test2']; 
              delete r.args['test']; 
              delete r.args['test']; /* remove duplicate arg, it needs to delete twice */ 
          } 
           
          r.args['gy'] = 'test'; 
          r.variables['args'] = 'test=test'; /* set entire args directly */ 

          Modification requestheader

          For request headers, if there are multiple identical headers, takes the first one for r.headersIn['name'];

          If you want to get or change all the repetitive headers, there are two ways:

          • As the following code shows, you first successively get and delete (if you don’t delete, you always get the first one), and reset to r.headersIn['name'] after splicing
          • Use r.variables['http_name'] (read-only, and it cannot be modified), for X-Forwarded-For, that is, r.variables['http_x_forwarded_for'] (note that the name in http_nameneeds converting to lowercase from uppercase, and the connector - shall be changed to underline_; for example, X-Forwarded-For is changed to http_x_forwarded_for).
          var xff = ''; 
          while (r.headersIn['X-Forwarded-For']) { /* remove duplicate header in loop */ 
              xff += r.headersIn['X-Forwarded-For'] + ', '; 
              delete r.headersIn['X-Forwarded-For']; 
          } 
           
          r.headersIn['X-Forwarded-For'] = xff.substring(0, xff.length - 2); 

          Mofidy the response header

          Set callback through r.respHeader(callback) to process the response header passed back by backend upstream, and similar with the request header, it need deleting multiple times, and then set again, with the code example shown as follows:

          Note: r.return/r.send/r.sendHeader/r.finish/r.internalRedirect/r.subrequest/r.respHeader(Itself) It cannot work in callback.

          function done() { 
              delete r.headersOut['dup']; 
              delete r.headersOut['dup']; 
              r.headersOut['dup'] = 'dup'; 
          } 
          r.respHeader(done); 

          A/B Test

          if (r.args['a']) { 
              r.args['version'] = 'new'; 
          } 
          else if (r.args['b']) { 
              r.args['version'] = 'old'; 
          } 

          Custom error page

          function done() { 
              if (r.status == 404) { 
                  r.status = 302; 
                  r.headersOut['Location'] = 'www.baidu.com/test'; 
              } 
          } 
           
          r.respHeader(done); 
          Previous
          EdgeJS Configuration Steps
          Next
          Statistical Analysis