本文共 3666 字,大约阅读时间需要 12 分钟。
Cannot modify header information - headers already sent by (output started at ...
本文旨在梳理此类问题的原因,触发条件以及相应的解法, 在介绍原因之前,先过一遍php runtime http trigger 使用的两种方式。
使用 php runtime http trigger 的时候中一般有两种使用方式:
使用方法,当不需要进行部署较大的php工程的使用方法, 比如:
"v1", "custom_header2" => ["v2", "v3"], "Set-Cookie" => urlencode("test php") . '=' . urlencode('test;more') ), "hello world" ); }
注意:强烈建议您所有返回的headers都放在构造Response对象的参数里面,如上面示例,不要单独使用能改变header的方法,比如 header 、 setcookie 等
此时的函数入口相当传统Apache/Nginx 的 conf 中 location, 将对应的php 文件送给 php-fpm 去解析,然后将解析后的结果返回给用户
函数计算为用户提供了一个 $GLOBALS['fcPhpCgiProxy']
对象用来和 php-fpm 进行交互,对
requestPhpCgi($request, $docRoot, $phpFile = "index.php", $fastCgiParams = [], $options = [])
requestPhpCgi
$request
: 跟 php http invoke
入口的参数一致$docRoot
: Web 工程的根目录$phpFile
: 用于拼接 cgi 参数中的 SCRIPT_FILENAME 的默认参数$fastCgiParams
: 函数计算内部尽量根据 $request
给您构造 default cgi params
, 但是如果您不是想要的,可以使用$fastCgiParams
覆盖一些参数 (reference: )$options
: array类型,可选参数, debug_show_cgi_params
设为 true
,会打印每次请求 php 解析时候的 cgi 参数, 默认为 false ;readWriteTimeout
设置解析的时间, 默认为 5 秒错误出现的原因简单描述就是当php 收到第一个 output (print, echo, )时,它会flush所有收集到的headers。然后它可以发送它想要的所有输出。但是这个时候再发送HTTP header是不允许的。详情可以参考:
通常来说就是用户第一种方式(不使用 fcPhpCgiProxy) 使用http trigger的时候,使用如下方法可能会出现以下问题:
不使用 fcPhpCgiProxy
"v1", "custom_header2" => ["v2", "v3"], "Set-Cookie" => urlencode("test php") . '=' . urlencode('test;more') ), "hello world");}
不单独使用能改变header的方法,比如 header 、 setcookie 等,将您所有返回的headers都放在构造Response对象的参数里面
使用fcPhpCgiProxy
至少两个文件, 一个入口函数文件,一个待解析的文件, for example:getAttribute("requestURI"); // parse $requestURI $proxy = $GLOBALS['fcPhpCgiProxy']; return $proxy->requestPhpCgi($request, __DIR__ . '/www', "a.php", ['SERVER_NAME' => 'abc.com']);}
" . "\n";echo "Simple Virtual HTML Document " . "\n";echo "" . $body . "\n";echo "REQUESTHEADERS: " . "\n";foreach ($_SERVER as $key => $value) { if (strpos($key, 'HTTP_') === 0) { echo $key . " : " . $value . PHP_EOL; }}echo "QUERYSTRING: " . $_SERVER['QUERY_STRING'] . PHP_EOL;echo "" . "Virtual HTML" . "
" . "
" . "\n";echo "Hey look. I just created a virtual (yep. virtual) HTML document!" . "\n";echo "" . "\n";?>
建议: 如果只是使用http trigger 实现类似一个api的功能,尽量不要使用fcPhpCgiProxy
, 即不要单独使用改变header的方法; 如果是类似一个web的工程的开发或者迁移,尽量使用fcPhpCgiProxy
由于函数计算serverless的特性,我们会把公共的东西放在nas目录,比如web 工程, 临时tmp缓存; 在php runtime使用场景中, session目录肯定是想放在nas 公共目录中的.
参考
只要是在php ini 可以设置的,我们都可以通过上述的方法达到目标,并且我们鼓励使用这种方法来裁剪不需要的extension, 比如针对session 设置,我们可以使用如下自定义的ini:
extension=session.soextension=ftp.soextension=shmop.soextension=bcmath.soextension=gettext.soextension=pcntl.soextension=simplexml.soextension=xmlreader.soextension=bz2.soextension=gmp.soextension=pdo.soextension=soap.soextension=xmlrpc.soextension=calendar.soextension=iconv.soextension=pdo_mysql.soextension=sockets.soextension=xmlwriter.soextension=ctype.soextension=imagick.soextension=phar.soextension=sysvmsg.soextension=dom.soextension=json.soextension=posix.soextension=sysvsem.soextension=exif.soextension=mbstring.soextension=protobuf.soextension=sysvshm.soextension=fileinfo.soextension=mysqli.soextension=redis.soextension=zip.soextension=memcached.soextension=tokenizer.sosession.save_path=/mnt/wwwsession.auto_start=1
最后两句用于session的设置,设置到nas的 /mnt/www
目录 并且自动开启
转载地址:http://itghx.baihongyu.com/