Nanao tahiry PyPI manokana aho miaraka amin'ny fanomezan-dΓ lana sy S3. Ao amin'ny Nginx

Amin'ity lahatsoratra ity dia te hizara ny traikefako amin'ny NJS aho, mpandika teny JavaScript ho an'ny Nginx novolavolain'i Nginx Inc, mamaritra ny fahaiza-manaony amin'ny fampiasana ohatra tena izy. Ny NJS dia ampahany amin'ny JavaScript izay ahafahanao manitatra ny fiasan'ny Nginx. Ho an'ny fanontaniana nahoana ny mpandika teny anao??? Namaly tamin'ny antsipiriany i Dmitry Volyntsev. Raha fintinina: NJS dia fomba nginx, ary ny JavaScript dia mandroso kokoa, "teratany" ary tsy misy GC, fa tsy toa an'i Lua.

Efa ela…

Tamin'ny asako farany dia nandova gitlab aho niaraka tamin'ny fantsona CI/CD maromaro miaraka amin'ny docker-compose, dind ary ny fahafinaretana hafa, izay nafindra tany amin'ny kaniko rails. Ireo sary nampiasaina teo aloha tao amin'ny CI dia nafindra tamin'ny endriny voalohany. Niasa tsara izy ireo mandra-pahatongan'ny andro niova ny IP gitlab anay ary nivadika ho voatavo ny CI. Ny olana dia ny iray amin'ireo sary docker izay nandray anjara tamin'ny CI dia nahitana git, izay nisintona ny maody Python tamin'ny ssh. Ho an'ny ssh dia mila fanalahidy manokana ianao ary ... tao amin'ny sary niaraka tamin'ny known_hosts. Ary ny CI rehetra dia tsy nahomby tamin'ny fahadisoana fanamarinana fototra noho ny tsy fitovizan'ny IP tena izy sy ilay voalaza ao amin'ny known_hosts. Nisy sary vaovao natambatra haingana avy amin'ny Dockfiles efa misy ary nampiana ny safidy StrictHostKeyChecking no. Saingy nijanona ny tsiro ratsy ary nisy ny faniriana hamindra ny libs ho any amin'ny tahiry PyPI manokana. Tombontsoa fanampiny, taorian'ny nifindrany tamin'ny PyPI manokana, dia fantsona tsotra sy famaritana mahazatra momba ny requirements.txt

Efa vita ny safidy, Tompokolahy!

Mitantana ny zava-drehetra ao amin'ny rahona sy Kubernetes izahay, ary tamin'ny farany dia naniry ny hahazo serivisy kely izay fitoeran-javatra tsy misy fanjakana misy fitahirizana ivelany. Eny, satria mampiasa S3 izahay dia nomena laharam-pahamehana izany. Ary, raha azo atao, miaraka amin'ny fanamarinana ao amin'ny gitlab (azonao ampidirinao izany raha ilaina).

Ny fikarohana haingana dia nahitana valiny maromaro: s3pypi, pypicloud ary safidy misy "manual" famoronana rakitra html ho an'ny turnips. Nanjavona ho azy ny safidy farany.

s3pypi: Ity dia cli amin'ny fampiasana fampiantranoana S3. Mampiakatra ny rakitra izahay, mamorona ny html ary mampiditra azy amin'ny siny iray ihany. Mety amin'ny fampiasana an-trano.

pypicloud: Toa tetikasa mahaliana ilay izy, saingy diso fanantenana aho rehefa avy namaky ny antontan-taratasy. Na dia eo aza ny antontan-taratasy tsara sy ny fahafahana manitatra mifanaraka amin'ny filanao, raha ny marina dia nivadika ho tafahoatra sy sarotra ny manamboatra izany. Ny fanitsiana ny kaody hifanaraka amin'ny asanao, araka ny tombantombana tamin'izany fotoana izany, dia naharitra 3-5 andro. Mila angon-drakitra ihany koa ny serivisy. Navelanay izany sao tsy nahita zavatra hafa.

Ny fikarohana lalindalina kokoa dia namoaka maody ho an'ny Nginx, ngx_aws_auth. Ny valin'ny fitsapana azy dia XML naseho tao amin'ny navigateur, izay mampiseho ny ao anatin'ny siny S3. Herintaona lasa izay no nanaovana ny fifampiraharahana farany tamin’ny fotoana nanaovana ny fikarohana. Toa nilaozana ny tahiry.

Amin'ny fandehanana any amin'ny loharano sy ny famakiana Pep-503 Tsapako fa ny XML dia azo ovaina ho HTML amin'ny lalitra ary omena pip. Rehefa avy nijery bebe kokoa momba an'i Nginx sy S3 aho dia nahita ohatra momba ny fanamarinana amin'ny S3 nosoratana tao amin'ny JS ho an'ny Nginx. Izay no nihaonako tamin'i NJS.

Raha raisina ho fototra ity ohatra ity, adiny iray taty aoriana dia hitako tao amin'ny navigateur-ko ilay XML mitovy amin'ny fampiasana ny module ngx_aws_auth, saingy efa voasoratra ao amin'ny JS ny zava-drehetra.

Tena tiako ny vahaolana nginx. Voalohany, antontan-taratasy tsara sy ohatra maro, faharoa, mahazo ny tsara rehetra an'i Nginx isika amin'ny fiasana amin'ny rakitra (avy ao anaty boaty), fahatelo, izay mahay manoratra configs ho an'i Nginx dia ho afaka hamantatra hoe inona izany. Ny minimalism koa dia tombony ho ahy, raha oharina amin'ny Python na Go (raha nosoratana avy amin'ny scratch), tsy lazaina intsony ny nexus.

TL;DR Taorian'ny andro 2 dia efa nampiasaina tamin'ny CI ny version test an'ny PyPi.

Ahoana no miasa?

Ny module dia ampidirina ao amin'ny Nginx ngx_http_js_module, tafiditra ao amin'ny sary ofisialy docker. Manafatra ny scripty izahay mampiasa ny torolΓ lana js_importmankany amin'ny konfigurasi Nginx. Ny asa dia antsoina amin'ny alΓ lan'ny torolΓ lana js_content. Ny torolalana dia ampiasaina mba hametrahana variables js_set, izay raisina ho tohan-kevitra afa-tsy ny asa voalaza ao amin'ny script. Saingy afaka manatanteraka subqueries ao amin'ny NJS isika raha tsy mampiasa Nginx, fa tsy XMLHttpRequest. Mba hanaovana izany, ny toerana mifanaraka amin'izany dia tsy maintsy ampiana amin'ny konfigurasi Nginx. Ary ny script dia tsy maintsy mamaritra ny subrequest amin'ity toerana ity. Mba hahafahana miditra amin'ny asa iray avy amin'ny config Nginx, ny anaran'ny asa dia tsy maintsy aondrana ao amin'ny script export default.

nginx.conf

load_module modules/ngx_http_js_module.so;
http {
  js_import   imported_name  from script.js;

server {
  listen 8080;
  ...
  location = /sub-query {
    internal;

    proxy_pass http://upstream;
  }

  location / {
    js_content imported_name.request;
  }
}

script.js

function request(r) {
  function call_back(resp) {
    // handler's code
    r.return(resp.status, resp.responseBody);
  }

  r.subrequest('/sub-query', { method: r.method }, call_back);
}

export default {request}

Rehefa nangatahana tao amin'ny navigateur http://localhost:8080/ miditra izahay location /izay ny toromarika js_content miantso asa request voalaza ao amin'ny scripty script.js. Ankehitriny, amin'ny asa request misy subquery atao amin'ny location = /sub-query, miaraka amin'ny fomba (ao amin'ny ohatra ankehitriny GET) azo avy amin'ny adihevitra (r), nandalo an-kolaka rehefa nantsoina io asa io. Ny valim-panontaniana manaraka dia hokarakaraina amin'ny asa call_back.

Andrana S3

Mba hanaovana fangatahana amin'ny fitahirizana S3 manokana dia mila:

ACCESS_KEY

SECRET_KEY

S3_BUCKET

Avy amin'ny fomba http ampiasaina, ny daty/ora amin'izao fotoana izao, S3_NAME ary URI, misy karazana tady miforona, izay nosoniavina (HMAC_SHA1) mampiasa SECRET_KEY. Manaraka dia tsipika toy ny AWS $ACCESS_KEY:$HASH, azo ampiasaina amin'ny lohatenin'ny fanomezan-dΓ lana. Tsy maintsy ampiana amin'ny lohapejy ny daty/ora mitovy amin'izay nampiasaina hamokarana ny tady tamin'ny dingana teo aloha X-amz-date. Ao amin'ny code dia toa izao:

nginx.conf

load_module modules/ngx_http_js_module.so;
http {
  js_import   s3      from     s3.js;

  js_set      $s3_datetime     s3.date_now;
  js_set      $s3_auth         s3.s3_sign;

server {
  listen 8080;
  ...
  location ~* /s3-query/(?<s3_path>.*) {
    internal;

    proxy_set_header    X-amz-date     $s3_datetime;
    proxy_set_header    Authorization  $s3_auth;

    proxy_pass          $s3_endpoint/$s3_path;
  }

  location ~ "^/(?<prefix>[w-]*)[/]?(?<postfix>[w-.]*)$" {
    js_content s3.request;
  }
}

s3.js(Ohatra fanomezan-dΓ lana AWS Sign v2, niova ho sata tsy ampiasaina)

var crypt = require('crypto');

var s3_bucket = process.env.S3_BUCKET;
var s3_access_key = process.env.S3_ACCESS_KEY;
var s3_secret_key = process.env.S3_SECRET_KEY;
var _datetime = new Date().toISOString().replace(/[:-]|.d{3}/g, '');

function date_now() {
  return _datetime
}

function s3_sign(r) {
  var s2s = r.method + 'nnnn';

  s2s += `x-amz-date:${date_now()}n`;
  s2s += '/' + s3_bucket;
  s2s += r.uri.endsWith('/') ? '/' : r.variables.s3_path;

  return `AWS ${s3_access_key}:${crypt.createHmac('sha1', s3_secret_key).update(s2s).digest('base64')}`;
}

function request(r) {
  var v = r.variables;

  function call_back(resp) {
    r.return(resp.status, resp.responseBody);
  }

  var _subrequest_uri = r.uri;
  if (r.uri === '/') {
    // root
    _subrequest_uri = '/?delimiter=/';

  } else if (v.prefix !== '' && v.postfix === '') {
    // directory
    var slash = v.prefix.endsWith('/') ? '' : '/';
    _subrequest_uri = '/?prefix=' + v.prefix + slash;
  }

  r.subrequest(`/s3-query${_subrequest_uri}`, { method: r.method }, call_back);
}

export default {request, s3_sign, date_now}

Fanazavana kely momba ny _subrequest_uri: miovaova io izay, miankina amin'ny uri voalohany, mamorona fangatahana amin'ny S3. Raha mila maka ny votoatin'ny "root" ianao, dia mila mamorona fangatahana uri manondro ny delimiter. delimiter, izay hamerina lisitr'ireo singa xml CommonPrefixes rehetra, mifanaraka amin'ny lahatahiry (raha ny PyPI, lisitry ny fonosana rehetra). Raha mila maka lisitry ny atiny amin'ny lahatahiry manokana ianao (lisitra misy ny dikan-teny rehetra), ny fangatahana uri dia tsy maintsy misy saha prefix misy ny anaran'ny lahatahiry (fonosana) tsy maintsy mifarana amin'ny slash /. Raha tsy izany dia mety hisy fifandonana rehefa mangataka ny votoatin'ny lahatahiry iray, ohatra. Misy lahatahiry aiohttp-fangatahana sy aiohttp-fangatahana ary raha ny fangatahana no mamaritra /?prefix=aiohttp-request, dia hisy ny votoatin'ny lahatahiry roa ny valiny. Raha misy slash amin'ny farany, /?prefix=aiohttp-request/, dia tsy hisy afa-tsy ny lahatahiry ilaina ny valiny. Ary raha mangataka rakitra isika, dia tsy tokony ho hafa noho ny tany am-boalohany ny uri vokatra.

Tehirizo ary avereno indray ny Nginx. Ao amin'ny navigateur dia miditra ny adiresin'ny Nginx izahay, ny valin'ny fangatahana dia XML, ohatra:

Lisitry ny lahatahiry

<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Name>myback-space</Name>
  <Prefix></Prefix>
  <Marker></Marker>
  <MaxKeys>10000</MaxKeys>
  <Delimiter>/</Delimiter>
  <IsTruncated>false</IsTruncated>
  <CommonPrefixes>
    <Prefix>new/</Prefix>
  </CommonPrefixes>
  <CommonPrefixes>
    <Prefix>old/</Prefix>
  </CommonPrefixes>
</ListBucketResult>

Avy amin'ny lisitry ny lahatahiry dia mila ireo singa ihany ianao CommonPrefixes.

Amin'ny fampidirana ny lahatahiry ilaintsika amin'ny adiresintsika ao amin'ny navigateur, dia hahazo ny votoatiny amin'ny endrika XML ihany koa isika:

Lisitry ny rakitra ao anaty lahatahiry

<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Name> myback-space</Name>
  <Prefix>old/</Prefix>
  <Marker></Marker>
  <MaxKeys>10000</MaxKeys>
  <Delimiter></Delimiter>
  <IsTruncated>false</IsTruncated>
  <Contents>
    <Key>old/giphy.mp4</Key>
    <LastModified>2020-08-21T20:27:46.000Z</LastModified>
    <ETag>&#34;00000000000000000000000000000000-1&#34;</ETag>
    <Size>1350084</Size>
    <Owner>
      <ID>02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4</ID>
      <DisplayName></DisplayName>
    </Owner>
    <StorageClass>STANDARD</StorageClass>
  </Contents>
  <Contents>
    <Key>old/hsd-k8s.jpg</Key>
    <LastModified>2020-08-31T16:40:01.000Z</LastModified>
    <ETag>&#34;b2d76df4aeb4493c5456366748218093&#34;</ETag>
    <Size>93183</Size>
    <Owner>
      <ID>02d6176db174dc93cb1b899f7c6078f08654445fe8cf1b6ce98d8855f66bdbf4</ID>
      <DisplayName></DisplayName>
    </Owner>
    <StorageClass>STANDARD</StorageClass>
  </Contents>
</ListBucketResult>

Avy amin'ny lisitry ny rakitra ihany no horaisintsika Key.

Ny hany sisa tavela dia ny manara-maso ny vokatra XML ary mandefa azy ho HTML, rehefa nosoloina voalohany ny lohatenin'ny Content-Type amin'ny lahatsoratra/html.

function request(r) {
  var v = r.variables;

  function call_back(resp) {
    var body = resp.responseBody;

    if (r.method !== 'PUT' && resp.status < 400 && v.postfix === '') {
      r.headersOut['Content-Type'] = "text/html; charset=utf-8";
      body = toHTML(body);
    }

    r.return(resp.status, body);
  }
  
  var _subrequest_uri = r.uri;
  ...
}

function toHTML(xml_str) {
  var keysMap = {
    'CommonPrefixes': 'Prefix',
    'Contents': 'Key',
  };

  var pattern = `<k>(?<v>.*?)</k>`;
  var out = [];

  for(var group_key in keysMap) {
    var reS;
    var reGroup = new RegExp(pattern.replace(/k/g, group_key), 'g');

    while(reS = reGroup.exec(xml_str)) {
      var data = new RegExp(pattern.replace(/k/g, keysMap[group_key]), 'g');
      var reValue = data.exec(reS);
      var a_text = '';

      if (group_key === 'CommonPrefixes') {
        a_text = reValue.groups.v.replace(///g, '');
      } else {
        a_text = reValue.groups.v.split('/').slice(-1);
      }

      out.push(`<a href="/mg/${reValue.groups.v}">${a_text}</a>`);
    }
  }

  return '<html><body>n' + out.join('</br>n') + 'n</html></body>'
}

Andrana PyPI

Hamarininay fa tsy misy tapaka na aiza na aiza amin'ireo fonosana fantatra fa miasa.

# Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ для тСстов Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅
python3 -m venv venv
. ./venv/bin/activate

# Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‡ΠΈΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹.
pip download aiohttp

# Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌ Π² ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½ΡƒΡŽ Ρ€Π΅ΠΏΡƒ
for wheel in *.whl; do curl -T $wheel http://localhost:8080/${wheel%%-*}/$wheel; done

rm -f *.whl

# УстанавливаСм ΠΈΠ· ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½ΠΎΠΉ Ρ€Π΅ΠΏΡ‹
pip install aiohttp -i http://localhost:8080

Averinay amin'ny libs izahay.

# Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ для тСстов Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅
python3 -m venv venv
. ./venv/bin/activate

pip install setuptools wheel
python setup.py bdist_wheel
for wheel in dist/*.whl; do curl -T $wheel http://localhost:8080/${wheel%%-*}/$wheel; done

pip install our_pkg --extra-index-url http://localhost:8080

Ao amin'ny CI, ny famoronana sy ny fametrahana fonosana dia toa izao:

pip install setuptools wheel
python setup.py bdist_wheel

curl -sSfT dist/*.whl -u "gitlab-ci-token:${CI_JOB_TOKEN}" "https://pypi.our-domain.com/${CI_PROJECT_NAME}"

fanamarinana

Ao amin'ny Gitlab dia azo atao ny mampiasa JWT ho fanamarinana / fanomezan-dΓ lana amin'ny serivisy ivelany. Amin'ny fampiasana ny torolalana auth_request ao Nginx, dia hamindra ny angon-drakitra fanamarinana amin'ny subrequest misy antso an-tariby ao amin'ny script. Ny script dia hanao subrequest hafa amin'ny url Gitlab ary raha voafaritra tsara ny angon-drakitra fanamarinana, dia hamerina ny code 200 ny Gitlab ary avela ny fampidinana / fampidinana ny fonosana. Maninona raha mampiasa subquery iray ary alefaso avy hatrany any amin'ny Gitlab ny angon-drakitra? Satria amin'izay fotoana izay dia tsy maintsy manitsy ny rakitra konfigurasi Nginx isika isaky ny manao fanovana amin'ny fanomezan-dΓ lana, ary asa mandreraka izany. Ary koa, raha mampiasa politikan'ny rafi-drakitra fakan-tsary mamaky fotsiny i Kubernetes, dia vao mainka sarotra kokoa izany rehefa manolo ny nginx.conf amin'ny configmap. Ary lasa tsy azo atao mihitsy ny manamboatra Nginx amin'ny alΓ lan'ny configmap raha mampiasa politika mandrΓ ra ny fampifandraisana ny volume (pvc) sy ny rafitra fichier root read-only (mitranga ihany koa izany).

Amin'ny fampiasana ny NJS intermediate, dia mahazo fahafahana manova ny mari-pamantarana voatondro ao amin'ny config nginx amin'ny fampiasana ny fari-piainan'ny tontolo iainana ary manao fisavana amin'ny script (ohatra, URL tsy voafaritra mazava).

nginx.conf

location = /auth-provider {
  internal;

  proxy_pass $auth_url;
}

location = /auth {
  internal;

  proxy_set_header Content-Length "";
  proxy_pass_request_body off;
  js_content auth.auth;
}

location ~ "^/(?<prefix>[w-]*)[/]?(?<postfix>[w-.]*)$" {
  auth_request /auth;

  js_content s3.request;
}

s3.js

var env = process.env;
var env_bool = new RegExp(/[Tt]rue|[Yy]es|[Oo]n|[TtYy]|1/);
var auth_disabled  = env_bool.test(env.DISABLE_AUTH);
var gitlab_url = env.AUTH_URL;

function url() {
  return `${gitlab_url}/jwt/auth?service=container_registry`
}

function auth(r) {
  if (auth_disabled) {
    r.return(202, '{"auth": "disabled"}');
    return null
  }

  r.subrequest('/auth-provider',
                {method: 'GET', body: ''},
                function(res) {
                  r.return(res.status, "");
                });
}

export default {auth, url}

Azo inoana fa mipoitra ny fanontaniana: -Nahoana no tsy mampiasa maody efa vita? Efa vita daholo ny rehetra! Ohatra, var AWS = mitaky('aws-sdk') ary tsy ilaina ny manoratra "bisikileta" misy fanamarinana S3!

Andeha isika hiroso amin'ny lafy ratsiny

Amiko dia lasa endri-javatra tsy mahafinaritra, nefa efa nantenaina ny tsy fahafahana manafatra mody JS ivelany. Voafaritra ao amin'ny ohatra etsy ambony mitaky('crypto') dia fananganana-in modules ary mitaky asa ho azy ireo ihany. Tsy misy fomba hampiasana indray ny code avy amin'ny scripts ary tsy maintsy mandika sy mametaka azy amin'ny rakitra samihafa ianao. Manantena aho fa indray andro any dia hampiharina io fampiasa io.

Tsy maintsy esorina ihany koa ny famatrarana ho an'ny tetikasa ankehitriny ao Nginx gzip off;

Satria tsy misy mΓ΄dely gzip ao amin'ny NJS ary tsy azo atao ny mampifandray azy; noho izany dia tsy misy fomba fiasa amin'ny angon-drakitra voaporitra. Marina fa tsy tena minus mihitsy ity raharaha ity. Tsy dia betsaka ny lahatsoratra, ary ny rakitra nafindra dia efa voatsindry ary tsy dia manampy azy ireo ny fanerena fanampiny. Ary koa, tsy serivisy feno entana na manakiana loatra ity ka tsy maintsy manahirana anao amin'ny fandefasana votoaty milliseconds vitsivitsy haingana kokoa.

Mitaky fotoana lava ny fanesorana ny script ary azo atao amin'ny alΓ lan'ny "printy" ao amin'ny error.log. Miankina amin'ny fampahalalana momba ny haavon'ny log, fampitandremana na fahadisoana, dia azo atao ny mampiasa fomba 3 r.log, r.warn, r.error tsirairay avy. Miezaka ny debug ny script sasany ao amin'ny Chrome (v8) na ny fitaovana console njs aho, saingy tsy azo jerena ao ny zava-drehetra. Rehefa debug kaody, antsoina hoe Functional Test, dia toa izao ny tantara:

docker-compose restart nginx
curl localhost:8080/
docker-compose logs --tail 10 nginx

ary mety hisy filaharana an-jatony toy izany.

Ny fanoratana kaody amin'ny alalan'ny subqueries sy ny variables ho azy ireo dia mivadika ho saro-takarina. Indraindray ianao dia manomboka mihazakazaka manodidina ny varavarankely IDE samihafa manandrana mamantatra ny filaharan'ny hetsika amin'ny codeo. Tsy sarotra izany fa indraindray dia mahasosotra be.

Tsy misy fanohanana feno ho an'ny ES6.

Mety misy lesoka hafa, saingy tsy nahita zavatra hafa aho. MizarΓ  vaovao raha manana traikefa ratsy amin'ny fampiasana NJS ianao.

famaranana

NJS dia mpandika teny misokatra malalaka izay ahafahanao mampihatra script JavaScript isan-karazany amin'ny Nginx. Nandritra ny fampivoarana azy, dia nojerena be ny fampisehoana. Mazava ho azy fa mbola be dia be ny tsy ampy, fa ny tetikasa dia novolavolain'ny ekipa kely ary mazoto manampy endri-javatra vaovao izy ireo ary manamboatra bibikely. Manantena aho fa indray andro any NJS dia hamela anao hampifandray ireo mΓ΄dely ivelany, izay hahatonga ny Nginx ho tsy voafetra. Saingy misy NGINX Plus ary azo inoana fa tsy hisy endri-javatra!

Repository misy kaody feno ho an'ny lahatsoratra

njs-pypi miaraka amin'ny fanohanana AWS Sign v4

Famaritana ny torolΓ lana momba ny module ngx_http_js_module

Repository ofisialin'ny NJS ΠΈ tahirin-kevitra

Ohatra amin'ny fampiasana NJS avy amin'i Dmitry Volintsev

njs - scripting JavaScript native in nginx / Kabary nataon'i Dmitry Volnyev tao amin'ny Saint HighLoad++ 2019

NJS amin'ny famokarana / Kabary nataon'i Vasily Soshnikov tao amin'ny HighLoad++ 2019

Manasonia sy manamarina ny fangatahana REST ao amin'ny AWS

Source: www.habr.com