问题描述
在需要用作技术堆栈的应用程序方面,我需要您的帮助:
我想将页面分成不同的部分并缓存其中的一些部分,因为生成速度很慢。
因此,我尝试按照文档https://symfony.com/doc/current/http_cache/ssi.html
中的说明使用SSI(服务器端包含)这是我的码头工人的配置:
FROM Nginx:1.19.2
copY docker-compose/Nginx /
ADD docker-compose/Nginx/Nginx.conf /etc/Nginx/Nginx.conf
ADD docker-compose/Nginx/symfony.dev.conf /etc/Nginx/conf.d/default.conf
和配置文件:
Nginx.conf
user www-data;
worker_processes 4;
pid /run/Nginx.pid;
events {
worker_connections 2048;
multi_accept on;
use epoll;
}
http {
server_tokens on;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 15;
types_hash_max_size 2048;
include /etc/Nginx/mime.types;
default_type application/octet-stream;
access_log on;
error_log on;
access_log /dev/stdout;
error_log /dev/stdout;
gzip on;
gzip_disable "msie6";
include /etc/Nginx/conf.d/*.conf;
include /etc/Nginx/sites-enabled/*;
open_file_cache max=300;
client_body_temp_path /tmp 1 2;
client_body_buffer_size 256k;
client_body_in_file_only off;
}
symfony.dev.conf
proxy_cache_path /tmp/Nginx levels=1:2 keys_zone=default:10m;
server {
listen 80;
root /var/www/html/symfony/public;
client_max_body_size 40M;
location = /health {
return 200 "healthy\n";
}
location = /ping {
return 200 "pong\n";
}
location / {
ssi on;
try_files $uri /index.PHP$is_args$args;
}
location ~ ^/index\.PHP(/|$) {
ssi on;
fastcgi_pass PHP-fpm:9000;
fastcgi_split_path_info ^(.+\.PHP)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_read_timeout 300;
internal;
}
location ~ \.PHP$ {
return 404;
}
location /status {
access_log off;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass PHP-fpm:9000;
fastcgi_index status.html;
}
error_log /var/log/Nginx/error.log;
access_log /var/log/Nginx/access.log;
}
如您所见,我在Web服务器上启用了SSI。
此外,我将其添加到框架的配置中(例如doc):
framework:
ssi: { enabled: true }
fragments: { path: /_fragment }
在模板/控制器中,我遵循文档:
模板
{{ render_ssi(controller('App\\Controller\\Pages\\HomeController::xxxx')) }}
控制器
public function xxxx() {
sleep(2);
$response = $this->render('pages/home/xxxx.html.twig',[
]);
$response->setSharedMaxAge(Constants::SSI_CACHE_TTL);
return $response;
}
sleep命令用于测试高速缓存和iss是否正常工作...
更多信息:
我在阅读文档后看到了供应商: render_ssi确保仅当请求具有诸如Surrogate-Capability这样的标头要求时才生成SSI指令:device =“ SSI / 1.0”(通常由网络服务器)。否则,它将直接嵌入子响应。
所以我尝试在代码中找到决定是否使用SSI的块:
vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.PHP
在此行:
/**
* {@inheritdoc}
*/
public function hasSurrogateCapability(Request $request)
{
if (null === $value = $request->headers->get('Surrogate-Capability')) {
return false;
}
return false !== strpos($value,sprintf('%s/1.0',strtoupper($this->getName())));
}
因此,我认为我的网络服务器不会将ISS-Header(Surrogate-Capability
)发送到我的PHP-fpm。
对于如何进行测试我没有任何想法...
谢谢大家能帮我...
致谢
编辑:
我创建的存储库以前遇到过相同的问题,您可以直接对其进行测试。
https://github.com/alessandro-candon/ssi-symfony
解决方法
我正在分享我以前私下给您的解决方案,因此每个人都可以使用它。
- 首先,由于您使用的是 fastcgi ,因此必须使用
fastcgi_cache_*
指令,
例如:
fastcgi_cache_path /tmp/nginx levels=1:2 keys_zone=foobar:10m;
代替
proxy_cache_path /tmp/nginx levels=1:2 keys_zone=foobar:10m;
- 由于Symfony使用唯一的查询字符串标识ssi片段,因此您必须在高速缓存键参数中包含查询字符串,
否则,您将始终缓存整个页面。您可以使用:
fastcgi_cache_key $scheme://$host$saved_uri$is_args$args;
我看到你打电话:
http://localhost:8101/home
它将匹配“ /”位置,然后nginx会向 ^ / index.php(/ | $)
问题在于,这样,当前的$uri
变量将被更改为“ index.php”,因此您将丢失“ / home”并且无法将其传递给Symfony(在该处进行处理)通过Symfony路由)。要解决此问题,请将其保存到自定义的nginx变量中:
set $saved_uri $uri;
然后,将其传递给fastcgi:
fastcgi_param REQUEST_URI $saved_uri;
注意默认情况下,REQUEST_URI
fastcgi参数设置为$request_uri
。如果您不更改它,Symfony也将始终收到curl(“ / home”)为ssi片段请求提供的路径!因此,在解决ssi包含项时,您将陷入无限循环。(请参阅:Wrong cache key for SSI-subrequests with FastCGI)
我建议您尽快添加默认的 fastcgi_params ,以便以后可以覆盖它们。如果将 include fastcgi_params 放在配置的底部,则默认值将覆盖您的自定义值。
- 您还必须考虑到,在内部请求ssi包含时,nginx 不会更新
$uri
变量。要解决此问题,请显式更新它。 (注意:由于先前描述的问题,这里我使用的是$saved_uri
而不是$uri
)。假设您正在使用 _fragment 来标识Symfony生成的ssi框架的路径,
您需要添加:
set $saved_uri /_fragment;
- 关于SSI标头:告诉Symfony nginx已启用ssi,
ssi on
指令还不够,因为nginx不会自动发送 Surrogate-Capability:device =“ SSI / 1.0“ 标头指向Symfony。
为此,请使用:
fastcgi_param HTTP_SURROGATE_CAPABILITY "device=\"SSI/1.0\"";
- 最后但并非最不重要的一点,请记住,定义缓存路径还不够,
您还需要告诉nginx使用它:
fastcgi_cache foobar;
最后,完整的配置将是:
fastcgi_cache_path /tmp/nginx levels=1:2 keys_zone=foobar:10m;
fastcgi_cache_key $scheme://$host$saved_uri$is_args$args; # The query string must be used here too,because Symfony uses it to identify the ssi fragment
server {
listen 80;
root /var/www/html/symfony/public;
client_max_body_size 40M;
include fastcgi_params; # We must put this here ahead,to let locations override the params
location = /health {
return 200 "healthy\n";
}
location = /ping {
return 200 "pong\n";
}
location /_fragment {
set $saved_uri /_fragment; # We hardcode the value because internal ssi requests DO NOT update the $uri variable !
try_files $uri /index.php$is_args$args;
internal;
}
location / {
set $saved_uri $uri; # We need this because the $uri is renamed later when making the internal request towards "index.php",so we would lose the original request !
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_cache foobar; # Remember to not use the directive "proxy_cache" fastcgi
add_header X-Cache-Status $upstream_cache_status; # Used for debugging
# NOTE nginx<->Symfony cache is NOT considered in this
fastcgi_param HTTP_SURROGATE_CAPABILITY "device=\"SSI/1.0\""; # Nginx doesn't pass this http header to Symfony even if ssi is on,but Symfony needs it to know if the proxy is able to use ssi
ssi on;
fastcgi_param REQUEST_URI $saved_uri; # IMPORTANT The included default "fastcgi_params" uses $request_uri,so internal requests are skipped ! This causes an infinite loop because of ssi inclusion.
fastcgi_param QUERY_STRING $args; # For some reason,we need to pass it again even if the included default "fastcgi_params" looks correct
fastcgi_pass php-fpm:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_read_timeout 300;
internal;
}
location ~ \.php$ {
return 404;
}
location /status {
access_log off;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php-fpm:9000;
fastcgi_index status.html;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
}