When JS meets Nginx

Many Web developers are not familiar with lua. Therefore, Nginx has introduced the NJS module, which can introduce JS scripts into Nginx configuration to implement some more complex Nginx configuration functions.

Install the NJS module

Nginx is required to be older than 1.9.11, since the load_module directive has only been supported since then

Method 1: Load the NJS module dynamically

Note: Different versions of Nginx require corresponding versions of the NJS module.

  1. Place the ngx_http_js_module.so file in the modules directory of the Nginx root directory,
  2. Add import module to nginx.conf
load_module modules/ngx_http_js_module.so;
load_module modules/ngx_stream_js_module.so;
Copy the code

Method two: add modules at compile time

  1. Download source code:

The repository is managed in Mercurial. You can download the source code hg clone http://hg.nginx.org/NJS using the hg command

  1. Nginx adds the following configuration at compile time
./configure --add-module=<path to NJS>/NJS/nginx
Copy the code

Second, the characteristics of the running environment of NJS module

NJS modules do not run a Nodejs, so Nginx JS can only be used as a middleware of Nginx like lua modules, not as a complete backend service.

1. The runtime environment is created at each request and destroyed at the end of the request

2. Non-blocking code execution

NJS uses an event-driven model to schedule the NJS runtime environment. When NJS performs a blocking operation (such as reading network data or making an external subrequest), Nginx suspends the execution of the current NJS VM and reschedule the event when it completes. So NJS code can be written in a simple linear fashion

3. Only partial ECAMA syntax is supported

NJS is based on the ECMAScript 5.1 specification and supports a list of syntax supported by some functions in ECMAScript 6 nginx.org/en/docs/NJS…

4. Tightly integrate request processing

Nginx processing a request involves several phases. Nginx directives usually run at a specified order to process requests. The Nginx module takes advantage of this ability to debug or modify a request. NJS module is also implemented in the form of instructions to run JS code logic at a specific stage.

NJS module support instructions and the corresponding processing stage

Processing phase The HTTP module The Stream module
Access – Authentication and access control auth_request and js_content js_access
The Pre – read – read/write content N/A js_preread
Filter – Read/write response during proxy js_body_filter js_header_filter js_filter
Content – Send response to client js_content N/A
Log/Variables — Evaluated on demand js_set js_set

Four simple usage examples of NJS

The following example defines a log format in JS

Create a logging.js file in the Nginx configuration directory

// File location: [nginx root directory]/conf/logging.js
// File contents: parses the request and prints out all the request headers
function logAllHeaders(r) {
    var log = `${r.variables.time_iso8601} client=${r.remoteAddress} method=${r.method} uri=${r.uri} status=${r.status}`;
    r.rawHeadersIn.forEach(h= > log += ` in.${h[0]}=${h[1]}`);
    r.rawHeadersOut.forEach(h= > log += ` out.${h[0]}=${h[1]}`);
    return log;
}

export default { logAllHeaders }
Copy the code

# Nginx configuration file

http {
   js_import  logging.js;      # js_import Loads a js script in the directory of the Nginx configuration file. The js file name will be used as the module namespace. A function can be referenced in the format of [file name].[function name]
   js_set     $log_all_headers logging.logAllHeaders; # js_set saves the output of the function logAllHeaders from the js file to the variable $log_all_headers.
   log_format kvpairs $log_all_headers;          # Customize a log format kvpairs
	
    server {
        listen 80;
        access_log /var/log/nginx/access.log kvpairs; # set the log format under this rule to the custom format aboveroot /usr/share/nginx/html; }}Copy the code

Five NJS supported directives

Reference documentation

NJS does not support many directives. Complex functions need to be used in conjunction with other Nginx directives.

Here are some common commands

Js_body_filter Modifies the body of response

Syntax:	js_body_filter function | module.function [buffer_type=string | buffer];
Default:	—
Context:	location, limit_except
This directive appeared in version 0.5.2.
Copy the code

The sample

/** * the function that handles the response body *@param { object } r- HTTP object *@param { buffer_type } data-Requested body data *@param { boolean } flags- Is the last data block */
function filter(r, data, flags) {
    r.sendBuffer(data.toLowerCase(), flags);
}
Copy the code

Js_content handles the return of the request

Syntax:	js_content function | module.function;
Default:	—
Context:	location, limit_except
Copy the code

The sample

http {
    # Introduce JS modules
    js_import  http.js;                 
    server {
        listen 80;
        location /content {
            # Specify the JS function to execute via the js_content directive
            js_contenthttp.content; }}}Copy the code
/ / HTTP js file
function content(r) {
    r.status = 200;
    r.headersOut['Content-Type'] = "text/plain; charset=utf-8";
    r.headersOut['Content-Length'] = 12;
    r.sendHeader();
    r.send("I am content");
    r.finish()
}

export default { content }
Copy the code

Js_header_filter modifies the returned request header

Syntax:	js_header_filter function | module.function;
Default:	—
Context:	location, limit_except
This directive appeared in version 0.5.1.
Copy the code

Js_import imports a JS file

Syntax:	js_import module.js | export_name from module.js;
Default:	—
Context:	http
This directive appeared in version 0.4.0.
Copy the code

The sample

http {
    # Introduce JS modules. The file name is used as the module's namespace. A function can be referenced in the format of [file name].[function name]
    js_import  http.js;                 
    server {
        listen 80;
        location /content {
            # Specify the JS function to execute via the js_content directivejs_content http.content; }}}Copy the code

Js_set sets variables

Syntax: js_set $variable function | module.function; Default: - the Context: HTTPCopy the code

The function referenced by this directive is executed when the variable is first referenced. And only synchronous operations are supported within the function

AD time

At present, wechat data center has a small number of front-end HCS, mainly responsible for the development of wechat big data-related systems, such as scheduling, BI, visualization, etc. Interested students are welcome to contact [email protected]

The resources

  • NJS supports THE JS syntax
  • Harnessing the Power and Convenience of JavaScript for Each Request with the NGINX JavaScript Module
  • NJS module documentation
  • The source code
  • NJS built-in objects, methods, functions
  • The sample