Nginx 의 하위 요청 (subrequest) 원리 분석
9827 단어 nginx
Nginx 의 하위 요청 디자인 은 자신의 다단 계 처리 절 차 를 바탕 으로 지정 한 url 에 대해 측로 요청 을 하 는 기능 을 실현 하고 보통 감 권, 미 러 등 기능 을 사용 합 니 다.물론 다른 용법 도 있 습 니 다. 여기 서 일일이 설명 하지 않 습 니 다. 보통 사용자 가 사용 하 는 인 터 페 이 스 는 auth 와 같 습 니 다.request 인터페이스 나 lua 의 capture 인터페이스.이 두 대외 인 터 페 이 스 는 모두 Nginx 의
ngx_http_subrequest
함 수 를 사용 했다.본문 은 그 하위 요청 절 차 를 약간 정리 하 였 다.배경 요구: Nginx 가 생명 주 기 를 요청 하 는 각 데이터 구 조 를 설명 하 는 데 사용 되 는 인식, 예 를 들 어
ngx_http_request_t
과 ngx_connection_t
.단순 업무
다음 설정 파일 은 외부 요청 이 / login 일 때 옆길 요청 을 하고 url 을 / auth 로 요청 합 니 다. 이 url 이 200 으로 돌아 간 후에 야 업 무 를 계속 할 수 있 습 니 다.물론 / auth 논 리 를 간소화 하기 위해 여 기 는 직접 / auth 아래 에서 2xx 를 되 돌려 주 었 습 니 다. 일반적인 상황 에서 복잡 한 업무 논리 가 있어 야 인증 을 완성 할 수 있 습 니 다.(auth request 상세 기능 은 여러분 이 직접 조회 하 세 요. 여 기 는 군말 하지 않 습 니 다).
location /login {
auth_request /auth/;
#
proxy_pass http://xxxx;
}
location /auth {
return 200 ok;
# proxy_pass http://ups;
}
Nginx 는 어떻게 측로 기능 을 실현 합 니까?검토 해 보 겠 습 니 다.
외부 요청 이 왔 을 때 먼저 Nginx 의 HTTP 일반적인 처 리 를 거 쳤 습 니 다. 즉, 프로 토 콜 을 분석 한 다음 에 location 에 일치 합 니 다. 이 단계 에서 처리 한 후에 access 단계 에 들 어가 면 access 단 계 는 content 단계 (즉 proxy pass) 앞 에 있 기 때문에 access 단계 의 흐름 은 proxy 보다 앞 설 수 있 습 니 다.패스 실행.
이 사례, 즉 위 에 파일 예 시 를 설정 한 authrequest 는 이 access 단계 함 수 를 실행 합 니 다.
호출 스 택 은 다음 과 같 습 니 다.
ngx_http_auth_request_handler
ngx_http_core_access_phase
ngx_http_core_run_phases
ngx_http_handler
ngx_http_process_request
xxxxx
Nginx 처리 절 차 를 잘 알 고 있다 면 이런 호출 스 택 은 매우 익숙 합 니 다.
ngx_http_auth_request_handler
각 단 계 를 순환 처리 하 는 데 사 용 됩 니 다. ngx_http_core_run_phases
는 하나의 패키지 이 고 실제 호출 은 구체 적 으로 등 록 된 ngx_http_core_access_phase
함수 입 니 다.ngx_http_auth_request_handler
함 수 는 무엇 을 합 니까?static ngx_int_t
ngx_http_auth_request_handler(ngx_http_request_t *r)
{
ngx_http_request_t *sr;
ngx_http_post_subrequest_t *ps;
ngx_http_auth_request_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module);
if (ctx != NULL) {
# , , ctx 。 。
}
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
ps->handler = ngx_http_auth_request_done;
ps->data = ctx;
ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps, NGX_HTTP_SUBREQUEST_WAITED);
return NGX_AGAIN;
}
위의 함수 에는 두 가지 관건 이 있 는데 첫 번 째 관건 은 호출
ngx_http_auth_request_handler
이 고 두 번 째 관건 은 ngx_http_subrequest
입 니 다. 후 자 를 먼저 말 하고 NGX 로 돌아 갑 니 다.AGAIN 때 는 외부 return NGX_AGAIN;
가 뒤의 단계 (content 단계) 를 실행 하지 않 는 순환 을 종료 하 는데, 이러한 목적 은 인증 이 완 료 된 후 뒤의 단 계 를 실행 하기 위 한 것 으로 'access' 논리 에 도 부합 한다.void
ngx_http_core_run_phases(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
ph = cmcf->phase_engine.handlers;
while (ph[r->phase_handler].checker) {
# ngx_http_core_access_phase ngx_http_auth_request_handler NGX_AGAIN , NGX_OK
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
if (rc == NGX_OK) {
return;
}
}
}
두 번 째 관건 점
ngx_http_core_run_phases
함수 다시 보 겠 습 니 다.ngx_int_t
ngx_http_subrequest(ngx_http_request_t *r,
ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,
ngx_http_post_subrequest_t *ps, ngx_uint_t flags)
{
ngx_http_request_t *sr;
# : 1, , r,
r->main->count++;
# ngx_http_request_t , ,
sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t));
# access url, location
ngx_http_update_location_config(sr);
# sr r posted_requests 。
return ngx_http_post_request(sr, NULL);
}
이 함 수 는 키 요청 데이터 구 조 를 만 들 고 아버지 가 요청 한 링크 에 걸 렸 을 뿐 처리 하지 않 은 것 같 습 니 다. 그 렇 죠?
그럼 이 요청 은 어디서 처 리 됩 니까?우 리 는 위의 호출 스 택 을 돌 이 켜 보고 마지막 으로 xxxx 를 사 용 했 습 니 다. 이 부분 은 협의 와 관련 이 있 기 때문에 HTTP 요청 에 대해
ngx_http_subrequest
입 니 다. HTTP 2 요청 에 대해 ngx_http_process_request_headers
입 니 다. 이 두 함 수 는 모두 하나 ngx_http_v2_run_request
함수 가 있 습 니 다.이 함 수 는 순환 처리 전에 생 성 된 하위 요청, 즉 처 리 된 sr 입 니 다.ngx_http_run_posted_requests(ngx_connection_t *c)
{
ngx_http_request_t *r;
ngx_http_posted_request_t *pr;
for ( ;; ) {
if (c->destroyed) {
return;
}
r = c->data;
pr = r->main->posted_requests;
if (pr == NULL) {
return;
}
r->main->posted_requests = pr->next;
# r ngx_http_subrequest sr
r = pr->request;
ngx_http_set_log_request(c->log, r);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http posted request: \"%V?%V\"", &r->uri, &r->args);
#write_event_handler ngx_http_handler, , , Nginx 。
r->write_event_handler(r);
}
}
그래서 여기까지, 우 리 는 하위 요청 이 처리 되 는 것 을 보 았 습 니 다. 처리 입 구 는 ngx 입 니 다.http_handler, 즉 하위 요청 은 처음부터 처 리 됩 니 다.그렇다면 자식 이 처 리 를 요청 한 후, 어떻게 아버 지 를 깨 워 자신의 남 은 단 계 를 계속 처리 해 달라 고 요청 합 니까?이것 은 HTTP 요청 방출 단계 와 관련 되 어 있 습 니 다. 모든 HTTP 요청 은 처리 가 끝 난 후에 (즉 응답 전송 완료) 함수 로 실 행 됩 니 다.
ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
{
......
# , auth_request , `ngx_http_auth_request_handler` `ngx_http_auth_request_done`, 。
if (r != r->main && r->post_subrequest) {
rc = r->post_subrequest->handler(r, r->post_subrequest->data, rc);
}
......
# , r r->main , r ,r->main
if (r != r->main) {
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (r->background) {
}
#
pr = r->parent;
if (r == c->data) {
#
r->main->count--;
if (!r->logged) {
if (clcf->log_subrequest) {
ngx_http_log_request(r);
}
r->logged = 1;
} else {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"subrequest: \"%V?%V\" logged again",
&r->uri, &r->args);
}
r->done = 1;
if (pr->postponed && pr->postponed->request == r) {
pr->postponed = pr->postponed->next;
}
c->data = pr;
} else {
}
# pr , post ,
if (ngx_http_post_request(pr, NULL) != NGX_OK) {
r->main->count++;
ngx_http_terminate_request(r, 0);
return;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http wake parent request: \"%V?%V\"",
&pr->uri, &pr->args);
return;
}
}
주의 하 세 요. 이때
ngx_http_run_posted_requests
함수 가 우리 ngx_http_post_request
에 있 기 때문에 위 에서 아버 지 를 자신 에 게 호출 ngx_http_finalize_request
하 라 고 요청 합 니 다. 그러면 바깥쪽 이 순환 할 때 아버지 가 요청 한 handler 를 실행 할 수 있 습 니 다.이 논 리 는 하위 요청 과 매우 비슷 하 며, 하위 요청 도 자신 을 post 대기 열 에 넣 습 니 다.이렇게 되면 아버지의 요청 이 회 복 됩 니 다.access 단계 에서 이 어 집 행 됩 니 다.
static ngx_int_t
ngx_http_auth_request_handler(ngx_http_request_t *r)
{
# ,
if (ctx != NULL) {
if (!ctx->done) {
return NGX_AGAIN;
}
/*
* as soon as we are done - explicitly set variables to make
* sure they will be available after internal redirects
*/
if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) {
return NGX_ERROR;
}
# , 200 , , 2xx , NGX_OK, ,
/* return appropriate status */
if (ctx->status == NGX_HTTP_FORBIDDEN) {
return ctx->status;
}
if (ctx->status == NGX_HTTP_UNAUTHORIZED) {
sr = ctx->subrequest;
h = sr->headers_out.www_authenticate;
if (!h && sr->upstream) {
h = sr->upstream->headers_in.www_authenticate;
}
if (h) {
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
r->headers_out.www_authenticate = ho;
}
return ctx->status;
}
if (ctx->status >= NGX_HTTP_OK
&& ctx->status < NGX_HTTP_SPECIAL_RESPONSE)
{
return NGX_OK;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"auth request unexpected status: %ui", ctx->status);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
물론 실제 구 덩이 는 많이 좋아 졌 습 니 다. nginx 코드 를 찾 아 보 세 요. 여기저기 r - > main 의 여러 가지 판단 이 여기저기 서 하위 요청 여 부 를 판단 해 야 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
간단! Certbot을 사용하여 웹 사이트를 SSL(HTTPS)화하는 방법초보자가 인프라 주위를 정돈하는 것은 매우 어렵습니다. 이번은 사이트를 간단하게 SSL화(HTTP에서 HTTPS통신)로 변경하는 방법을 소개합니다! 이번에는 소프트웨어 시스템 Nginx CentOS7 의 환경에서 S...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.