Ua hana au i kaʻu waihona PyPI ponoʻī me ka ʻae a me S3. Ma ka Nginx

Ma kēia ʻatikala makemake wau e kaʻana like i kaʻu ʻike me NJS, kahi unuhi ʻōlelo JavaScript no Nginx i hoʻomohala ʻia e Nginx Inc, e wehewehe ana i kāna mau mana nui e hoʻohana ana i kahi hiʻohiʻona maoli. ʻO NJS kahi ʻāpana o JavaScript e hiki ai iā ʻoe ke hoʻonui i ka hana o Nginx. I ka ninau no ke aha kou unuhi ʻōlelo ponoʻī??? Ua pane ʻo Dmitry Volyntsev i nā kikoʻī. ʻO ka pōkole: ʻo NJS ke ala nginx, a ʻoi aku ka holomua o JavaScript, "ʻōiwi" a ʻaʻohe GC, ʻaʻole like me Lua.

I ka wā kahiko loa…

Ma kaʻu hana hope loa, ua hoʻoili au i ka gitlab me ka nui o nā motley CI/CD pipelines me docker-compose, dind a me nā mea leʻaleʻa ʻē aʻe, i hoʻoili ʻia i nā kaniko. Ua hoʻoneʻe ʻia nā kiʻi i hoʻohana mua ʻia ma CI i ko lākou ʻano kumu. Ua hana maikaʻi lākou a hiki i ka lā i hoʻololi ai kā mākou gitlab IP a lilo ʻo CI i paukena. ʻO ka pilikia ʻo ia kekahi o nā kiʻi docker i komo i ka CI i git, nāna i huki i nā modula Python ma o ssh. No ka ssh pono ʻoe i kahi kī pilikino a ... aia ma ke kiʻi me nā known_hosts. A ua hāʻule kekahi CI me kahi hewa hōʻoia nui ma muli o kahi mismatch ma waena o ka IP maoli a me ka mea i kuhikuhi ʻia ma known_hosts. Ua hōʻuluʻulu koke ʻia kahi kiʻi hou mai nā Dockfiles e kū nei a ua hoʻohui ʻia ke koho StrictHostKeyChecking no. Akā ua mau ka ʻono maikaʻi ʻole a aia ka makemake e neʻe i nā libs i kahi waihona pilikino PyPI. ʻO kahi bonus hou, ma hope o ka hoʻololi ʻana iā PyPI pilikino, he pipeline maʻalahi a me kahi wehewehe maʻamau o nā koi.txt

Ua koho ʻia, e nā kāne!

Holo mākou i nā mea āpau ma nā ao a me nā Kubernetes, a i ka hopena ua makemake mākou e kiʻi i kahi lawelawe liʻiliʻi he pahu mokuʻāina ʻole me ka waiho waho. ʻAe, ʻoiai mākou e hoʻohana iā S3, ua hāʻawi ʻia ka mea nui iā ia. A, inā hiki, me ka hōʻoia ma gitlab (hiki iā ʻoe ke hoʻohui iā ʻoe iho inā pono).

Ua loaʻa i ka huli wikiwiki nā hopena he nui: s3pypi, pypicloud a me kahi koho me ka hana "manual" o nā faila html no nā turnips. Ua nalowale ka koho hope loa iā ia iho.

s3pypi: He cli kēia no ka hoʻohana ʻana i ka hoʻokipa S3. Hoʻouka mākou i nā faila, hana i ka html a hoʻouka iā ia i ka bākeke hoʻokahi. He kūpono no ka hoʻohana home.

pypicloud: Ua like ia me kahi papahana hoihoi, akā ma hope o ka heluhelu ʻana i ka palapala, ua hoka wau. ʻOiai nā palapala maikaʻi a me ka hiki ke hoʻonui e kūpono i kāu mau pono, ʻoiaʻiʻo ua hoʻololi ʻia a paʻakikī hoʻi e hoʻonohonoho. ʻO ka hoʻoponopono ʻana i ke code e kūpono i kāu mau hana, e like me nā manaʻo i kēlā manawa, e lawe ʻia i nā lā 3-5. Pono ka lawelawe i kahi waihona. Haʻalele mākou inā ʻaʻole i loaʻa iā mākou kekahi mea ʻē aʻe.

Ua loaʻa kahi ʻimi hohonu i kahi module no Nginx, ngx_aws_auth. ʻO ka hopena o kāna hoʻāʻo ʻana ʻo ia ka XML i hōʻike ʻia ma ka polokalamu kele pūnaewele, e hōʻike ana i nā mea o ka bakeke S3. ʻO ka hana hope loa i ka manawa o ka ʻimi ʻana he makahiki i hala. Ua haʻalele ʻia ka waihona.

Ma ka hele ʻana i ke kumu a heluhelu PEP-503 Uaʻike wau e hiki ke hoʻololi i ka XML i HTML ma ka lele a hāʻawiʻia i ka pip. Ma hope o ka googling hou aʻe e pili ana iā Nginx a me S3, ua ʻike au i kahi hiʻohiʻona o ka hōʻoia ʻana ma S3 i kākau ʻia ma JS no Nginx. ʻO ia koʻu ʻike ʻana iā NJS.

I ka lawe ʻana i kēia hiʻohiʻona ma ke kumu, hoʻokahi hola ma hope ua ʻike au i kaʻu polokalamu kele i ka XML like me ka hoʻohana ʻana i ka module ngx_aws_auth, akā ua kākau ʻia nā mea āpau ma JS.

Ua makemake nui au i ka hoʻonā nginx. ʻO ka mea mua, nā palapala maikaʻi a me nā hiʻohiʻona he nui, ʻo ka lua, loaʻa iā mākou nā mea maikaʻi a pau o Nginx no ka hana ʻana me nā faila (mai loko o ka pahu), ʻo ke kolu, ʻo ka mea ʻike pehea e kākau ai i nā configs no Nginx e hiki ke ʻike i ka mea. ʻO ka Minimalism kekahi mea hoʻohui iaʻu, i hoʻohālikelike ʻia me Python a i ʻole Go (inā kākau ʻia mai ka ʻōpala), ʻaʻole e haʻi i ka nexus.

TL; DR Ma hope o 2 mau lā, ua hoʻohana ʻia ka mana hoʻāʻo o PyPi ma CI.

Pehea ia hana?

Hoʻokomo ʻia ka module i Nginx ngx_http_js_module, i komo i loko o ke kiʻi docker mana. Hoʻokomo mākou i kā mākou palapala me ka hoʻohana ʻana i ke kuhikuhi js_importi ka hoʻonohonoho Nginx. Kāhea ʻia ka hana e kahi kuhikuhi js_content. Hoʻohana ʻia ke kuhikuhi no ka hoʻonohonoho ʻana i nā loli js_set, ka mea i hoʻopaʻapaʻa wale i ka hana i wehewehe ʻia ma ka palapala. Akā hiki iā mākou ke hoʻokō i nā subqueries ma NJS me ka hoʻohana wale ʻana iā Nginx, ʻaʻole kekahi XMLHttpRequest. No ka hana ʻana i kēia, pono e hoʻohui ʻia ka wahi kūpono i ka hoʻonohonoho Nginx. A pono e wehewehe ka palapala i kahi subrequest i kēia wahi. I mea e hiki ai ke komo i kahi hana mai ka config Nginx, pono e lawe ʻia ka inoa hana i loko o ka palapala ponoʻī 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}

Ke noi ʻia ma ka polokalamu kele pūnaewele http://localhost:8080/ komo mākou i loko location /ma kahi o ke kuhikuhi js_content kāhea i kahi hana request i wehewehe ʻia ma kā mākou palapala script.js. I ka huli, i ka hana request hana ʻia kahi subquery i location = /sub-query, me kahi ala (ma ka laʻana o kēia manawa GET) i loaʻa mai ka hoʻopaʻapaʻa (r), ua hala implicitly ke kāhea ʻia kēia hana. E hana ʻia ka pane subrequest i ka hana call_back.

Ke ho'āʻo nei iā S3

No ke noi ʻana i kahi waihona S3 pilikino, pono mākou:

ACCESS_KEY

SECRET_KEY

S3_BUCKET

Mai ke ʻano http i hoʻohana ʻia, ka lā/manawa o kēia manawa, S3_NAME a me URI, hoʻokumu ʻia kekahi ʻano kaula, i kau inoa ʻia (HMAC_SHA1) me SECRET_KEY. He laina like ka hope AWS $ACCESS_KEY:$HASH, hiki ke hoʻohana ʻia ma ke poʻo ʻae. Pono e hoʻohui ʻia ka lā/manawa like i hoʻohana ʻia no ka hana ʻana i ke kaula i ka ʻanuʻu mua i ke poʻo X-amz-date. Ma ke code e like me kēia:

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(AWS Sign v2 hiʻohiʻona mana, hoʻololi i ke kūlana hoʻopau ʻia)

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}

He wehewehe iki no _subrequest_uri: he hoololi keia, ma muli o ka uri mua, e hana i kahi noi i S3. Inā pono ʻoe e kiʻi i nā mea o ka "root", a laila pono ʻoe e hana i kahi noi uri e hōʻike ana i ka delimiter. delimiter, ka mea e hoʻihoʻi i ka papa inoa o nā mea CommonPrefixes xml a pau, e pili ana i nā papa kuhikuhi (i ka hihia o PyPI, he papa inoa o nā pūʻolo āpau). Inā pono ʻoe e kiʻi i kahi papa inoa o nā mea i loko o kahi papa kuhikuhi kikoʻī (kahi papa inoa o nā ʻāpana ʻāpana āpau), a laila pono i ka noi uri ke loaʻa kahi kahua prefix me ka inoa o ka papa kuhikuhi (package) pono e pau me kahi slash /. A i ʻole, hiki ke hui ʻia ke noi ʻana i nā mea o kahi papa kuhikuhi, no ka laʻana. Aia nā papa kuhikuhi aiohttp-noi a me aiohttp-noi a inā e kuhikuhi ka noi /?prefix=aiohttp-request, a laila e loaʻa i ka pane nā ʻike o nā papa kuhikuhi ʻelua. Ina he slash ma ka hope, /?prefix=aiohttp-request/, a laila e loaʻa i ka pane ka papa kuhikuhi pono wale nō. A inā noi mākou i faila, ʻaʻole pono e ʻokoʻa ka uri i loaʻa mai ka mea mua.

E mālama a hoʻomaka hou i ka Nginx. Ma ka polokalamu kele pūnaewele mākou e komo i ka helu o kā mākou Nginx, ʻo ka hopena o ka noi e XML, no ka laʻana:

Papa papa kuhikuhi

<?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>

Mai ka papa inoa o nā papa kuhikuhi e pono wale ʻoe i nā mea CommonPrefixes.

Ma ka hoʻohui ʻana i ka papa kuhikuhi e pono ai mākou i kā mākou helu wahi ma ka polokalamu kele pūnaewele, e loaʻa nō hoʻi iā mākou nā ʻike ma ka palapala XML:

Ka papa inoa o nā faila ma kahi papa kuhikuhi

<?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>

Mai ka papa inoa o nā faila e lawe mākou i nā mea wale nō Key.

ʻO nā mea a pau i koe, ʻo ia ka hoʻokaʻawale ʻana i ka XML hopena a hoʻouna iā ia ma ke ʻano he HTML, me ka hoʻololi mua ʻana i ke poʻomanaʻo Content-Type me ka kikokikona/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="/haw/${reValue.groups.v}">${a_text}</a>`);
    }
  }

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

Ke ho'āʻo nei iā PyPI

Nānā mākou ʻaʻohe mea e haki ma nā wahi āpau i ʻike ʻia e hana.

# Создаем для тестов новое окружение
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

Hana hou mākou me kā mākou libs.

# Создаем для тестов новое окружение
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

Ma CI, ka hana ʻana a me ka hoʻouka ʻana i kahi pūʻolo e like me kēia:

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}"

Kalaukina

Ma Gitlab hiki ke hoʻohana iā JWT no ka hōʻoia / ʻae ʻana i nā lawelawe o waho. Ke hoʻohana nei i ka auth_request kuhikuhi ma Nginx, e hoʻihoʻi mākou i ka ʻikepili hōʻoia i kahi subrequest i loaʻa kahi kelepona hana ma ka palapala. E hana hou ka palapala i ka url Gitlab a inā i kuhikuhi pololei ʻia ka ʻikepili hōʻoia, a laila e hoʻihoʻi ʻo Gitlab i ke code 200 a e ʻae ʻia ka hoʻouka ʻana / hoʻoiho o ka pōʻai. No ke aha e hoʻohana ʻole ai i hoʻokahi subquery a hoʻouna koke i ka ʻikepili i Gitlab? No ka mea, pono mākou e hoʻoponopono i ka faila hoʻonohonoho Nginx i kēlā me kēia manawa a mākou e hoʻololi ai i ka mana, a he hana paʻakikī kēia. Eia kekahi, inā hoʻohana ʻo Kubernetes i kahi kulekele waihona waihona waihona heluhelu wale nō, a laila hoʻohui hou kēia i ka paʻakikī ke hoʻololi i ka nginx.conf ma o ka configmap. A lilo loa ia i mea hiki ʻole ke hoʻonohonoho iā Nginx ma o ka configmap i ka manawa like me ka hoʻohana ʻana i nā kulekele e pāpā ana i ka hoʻopili ʻana o nā volumes (pvc) a me ka waihona waihona waihona heluhelu-wale nō (hiki pū kēia).

Ke hoʻohana nei i ka NJS intermediate, loaʻa iā mākou ka manawa e hoʻololi i nā ʻāpana kikoʻī i ka nginx config me ka hoʻohana ʻana i nā mea hoʻololi kaiapuni a hana i kekahi mau loiloi i ka script (no ka laʻana, kahi URL i kuhikuhi hewa ʻia).

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}

Loaʻa paha ka nīnau: -No ke aha e hoʻohana ʻole ai i nā modula i hana ʻia? Ua hana ʻia nā mea a pau ma laila! No ka laʻana, var AWS = koi('aws-sdk') a ʻaʻohe pono e kākau i kahi "paika" me ka hōʻoia S3!

E neʻe kāua i ka cons

Noʻu, ʻo ka hiki ʻole ke hoʻokomo i nā modula JS waho i lilo i mea leʻaleʻa, akā i manaʻo ʻia. I wehewehe ʻia ma ka laʻana ma luna nei koi('crypto'). nā modules kūkulu ʻia a koi aku i na hana no lakou. ʻAʻohe ala e hoʻohana hou ai i ke code mai nā palapala a pono ʻoe e kope a paʻi i loko o nā faila like ʻole. Manaʻo wau e hoʻokō ʻia kēia hana i kekahi lā.

Pono e hoʻopau ʻia ka hoʻopili ʻana no ka papahana o kēia manawa ma Nginx gzip off;

No ka mea, ʻaʻohe module gzip ma NJS a ʻaʻole hiki ke hoʻopili iā ia; no laila, ʻaʻohe ala e hana ai me ka ʻikepili i hoʻopili ʻia. ʻOiaʻiʻo, ʻaʻole kēia he minus no kēia hihia. ʻAʻole nui ka kikokikona, a ua hoʻopili ʻia nā faila i hoʻoili ʻia a ʻaʻole kōkua nui ka hoʻopiʻi hou iā lākou. Eia kekahi, ʻaʻole kēia he lawelawe hoʻouka a koʻikoʻi paha āu e hoʻopilikia ai i ka hāʻawi ʻana i nā ʻike i kekahi mau milliseconds wikiwiki.

ʻO ka hoʻopau ʻana i ka ʻatikala e lōʻihi ka manawa a hiki wale ma o "paʻi" ma error.log. Ma muli o ka ʻike pae logging i hoʻonohonoho ʻia, warn a hewa paha, hiki ke hoʻohana i nā ʻano 3 r.log, r.warn, r.error i kēlā me kēia. Ke ho'āʻo nei au e hoʻopau i kekahi mau palapala ma Chrome (v8) a i ʻole ka hāmeʻa console njs, akā ʻaʻole hiki ke nānā ʻia nā mea āpau ma laila. Ke hoʻopau i ka code, aka hoʻāʻo hana, ʻike ʻia ka mōʻaukala penei:

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

a hiki ke loaʻa he mau haneli o ia mau kaʻina.

ʻO ke kākau ʻana i ke code me ka hoʻohana ʻana i nā subqueries a me nā mea hoʻololi no lākou e lilo i kuʻekuʻe wāwae. I kekahi manawa hoʻomaka ʻoe e holo a puni nā IDE like ʻole windows e hoʻāʻo nei e noʻonoʻo i ke ʻano o nā hana o kāu code. ʻAʻole paʻakikī, akā i kekahi manawa he mea hoʻonāukiuki loa.

ʻAʻohe kākoʻo piha no ES6.

Aia kekahi mau hemahema ʻē aʻe, akā ʻaʻole wau i ʻike i kekahi mea ʻē aʻe. Kaʻana like i ka ʻike inā loaʻa iā ʻoe kahi ʻike maikaʻi ʻole me ka hoʻohana ʻana iā NJS.

hopena

ʻO NJS kahi wehewehe wehewehe māmā māmā e hiki ai iā ʻoe ke hoʻokō i nā palapala JavaScript like ʻole ma Nginx. I ka wā o kona hoʻomohala ʻana, ua nānā nui ʻia ka hana. ʻOiaʻiʻo, he nui nā mea i nalowale, akā ke kūkulu ʻia nei ka papahana e kahi hui liʻiliʻi a ke hoʻohui nei lākou i nā hiʻohiʻona hou a hoʻoponopono i nā pōpoki. Manaʻo wau i kekahi lā e ʻae ʻo NJS iā ʻoe e hoʻopili i nā modula waho, kahi e hana ai ʻo Nginx i ka palena ʻole. Akā aia ʻo NGINX Plus a ʻaʻole paha he mau hiʻohiʻona!

Waihona me ka helu piha no ka ʻatikala

njs-pypi me ke kākoʻo AWS Sign v4

ʻO ka wehewehe ʻana i nā kuhikuhi o ka module ngx_http_js_module

Waihona NJS kūhelu и ka palapala

Nā hiʻohiʻona o ka hoʻohana ʻana iā NJS mai Dmitry Volintsev

njs - ka palapala JavaScript maoli ma ka nginx / ʻŌlelo a Dmitry Volnyev ma Saint HighLoad++ 2019

NJS i ka hana / ʻŌlelo a Vasily Soshnikov ma HighLoad++ 2019

Kau inoa a hōʻoia i nā noi REST ma AWS

Source: www.habr.com