常见问题

如何处理静态资源

Apache URl rewrite

  1. <IfModule mod_rewrite.c>
  2. Options +FollowSymlinks
  3. RewriteEngine On
  4. RewriteCond %{REQUEST_FILENAME} !-d
  5. RewriteCond %{REQUEST_FILENAME} !-f
  6. # RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] fcgi下无效
  7. RewriteRule ^(.*)$ http://127.0.0.1:9501/$1 [QSA,P,L]
  8. # 请开启 proxy_mod proxy_http_mod request_mod
  9. </IfModule>

Nginx URl rewrite

  1. server {
  2. root /data/wwwroot/;
  3. server_name local.swoole.com;
  4. location / {
  5. proxy_http_version 1.1;
  6. proxy_set_header Connection "keep-alive";
  7. proxy_set_header X-Real-IP $remote_addr;
  8. if (!-f $request_filename) {
  9. proxy_pass http://127.0.0.1:9501;
  10. }
  11. }
  12. }

Swoole 静态文件处理器

详细请可查看 配置文件 章节

修改配置文件的 dev.php 或者 produce.php,实现 Swoole 对静态文件进行处理。

  1. <?php
  2. return [
  3. // ...... 这里省略
  4. 'MAIN_SERVER' => [
  5. // ...... 这里省略
  6. 'SETTING' => [
  7. // ...... 这里省略
  8. # 设置处理 Swoole 静态文件
  9. 'document_root' => EASYSWOOLE_ROOT . '/Static/',
  10. 'enable_static_handler' => true,
  11. ],
  12. // ...... 这里省略
  13. ],
  14. // ...... 这里省略
  15. ];

上述配置是假设你的项目根目录有个 Static 目录是用来放置静态文件的。具体的使用可查看 https://wiki.swoole.com/#/http_server?id=document_root

关于跨域处理

在框架的初始化事件 initialize 事件 中进行注册。

注册示例代码如下:

  1. public static function initialize()
  2. {
  3. date_default_timezone_set('Asia/Shanghai');
  4. // onRequest v3.4.x+
  5. \EasySwoole\Component\Di::getInstance()->set(\EasySwoole\EasySwoole\SysConst::HTTP_GLOBAL_ON_REQUEST, function (\EasySwoole\Http\Request $request, \EasySwoole\Http\Response $response) {
  6. $response->withHeader('Access-Control-Allow-Origin', '*');
  7. $response->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  8. $response->withHeader('Access-Control-Allow-Credentials', 'true');
  9. $response->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
  10. if ($request->getMethod() === 'OPTIONS') {
  11. $response->withStatus(\EasySwoole\Http\Message\Status::CODE_OK);
  12. return false;
  13. }
  14. return true;
  15. });
  16. }

EasySwoole 3.4.x 版本之前:可在项目根目录的 EasySwooleEvent.php 中看到 onRequestafterRequest 方法.

如何获取 $HTTP_RAW_POST_DATA

  1. $content = $this->request()->getBody()->__toString();
  2. $raw_array = json_decode($content, true);

如何获取客户端 IP

举例,如何在控制器中获取客户端 IP

  1. // 真实地址
  2. // 获取连接的文件描述符
  3. $fd = $this->request()->getSwooleRequest()->fd;
  4. $ip = \EasySwoole\EasySwoole\ServerManager::getInstance()->getSwooleServer()->connection_info($fd);
  5. var_dump($ip);
  6. // header 地址,例如经过 nginx proxy 后
  7. $ip2 = $this->request()->getHeaders();
  8. var_dump($ip2);

HTTP 状态码总为500

自 swoole 1.10.x2.1.x 版本起,执行 http server 回调中,若未执行 response->end(),则全部返回 500 状态码

如何 setCookie

调用 response 对象的 setCookie 方法即可设置 cookiesetCookie 方法和原生 setcookie 用法一致。

  1. $this->response()->setCookie('name', 'value');

更多操作可看 Response 对象

如何自定义 App 命名空间对应目录

只需要修改项目根目录的 composer.json 的自动加载的 App 命名空间对应的目录即可,然后执行 composer dumpautolaod -o 注册就行。

  1. {
  2. // ... 这里省略
  3. "autoload": {
  4. "psr-4": {
  5. "App\\": "Application/"
  6. }
  7. }
  8. }

如何启用 Https

通常建议使用 Nginx 或者 Lb 来配置证书,将 https 请求解析为 http 反代到 swoole

如果你仅是测试使用,可以在配置文件 (dev.php 或者 produce.php) 中添加和修改以下配置来启用https。

  1. <?php
  2. return [
  3. // ...... 这里省略
  4. 'MAIN_SERVER' => [
  5. // ...... 这里省略
  6. 'SOCK_TYPE' => SWOOLE_TCP | SWOOLE_SSL, // 默认是 SWOOLE_TCP
  7. 'SETTING' => [
  8. 'ssl_cert_file' => '证书路径,仅支持.pem格式',
  9. 'ssl_key_file' => '私钥路径',
  10. ]
  11. // ...... 这里省略
  12. ],
  13. // ...... 这里省略
  14. ];

详细请可查看 配置文件 章节

DNS Lookup resolve timeout 错误

该错误一般存在于 http 客户端并发调用时产生,原因是 dns 效率慢,导致多线程获取 dns 时超时,包括不限于以下场景:

  • mysql host 设置为域名形式,并且设置最小连接高于 2(很难看到,一般是 10 才会偶尔报错)
  • HTTPClient 多个协程同时并发
  • csp 并发编程 等

解决方法为:
在并发之前,预先使用 Swoole\Coroutine::gethostbyname('www.baidu.com'); 去查询一次dns ipswoole 底层才会自动缓存该 ip

例如:

  1. Swoole\Coroutine::gethostbyname('www.baidu.com');
  2. for ($j = 0; $j < 100; $j++) {
  3. go(function () use ($j) {
  4. for ($i = 0; $i < 1000; $i++) {
  5. $client = new Swoole\Coroutine\Http\Client('www.baidu.com', 443, true);
  6. $client->get('/');
  7. if (empty($client->errMsg)) {
  8. //var_dump($client->getBody());
  9. } else {
  10. var_dump($client->errMsg);
  11. }
  12. }
  13. });
  14. }

CURL 发送 POST请求 EasySwoole 服务器端超时

  • 出现原因:CURL 在发送较大的 POST 请求(例如: 上传文件)时会先发一个 100-continue 的请求,如果收到服务器的回应才会发送实际的 POST 数据。而 swoole_http_server(即 EasySwooleHttp 主服务) 不支持 100-continue,就会导致 CURL 请求超时。
  • 解决方法:

方法1:关闭 CURL100-continue,在 CURLHeader 中配置关闭 100-continue 选项。

示例代码(php):

  1. <?php
  2. // 创建一个新cURL资源
  3. $ch = curl_init();
  4. // 设置URL和相应的选项
  5. curl_setopt($ch, CURLOPT_URL, "http://127.0.0.1:9501");
  6. curl_setopt($ch, CURLOPT_HEADER, 0);
  7. curl_setopt($ch, CURLOPT_POST, 1); // 设置为POST方式
  8. curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); // 关闭 `CURL` 的 `100-continue`
  9. curl_setopt($ch, CURLOPT_POSTFIELDS, array('test' => str_repeat('a', 800000)));// POST 数据
  10. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

方法2:使用 Nginx 做前端代理,由 Nginx 处理 100-Continue(针对无法关闭 100-continue时)