关于nginx http code 499的错误

最近在查看nginx日志的的时候,发现了一些状态码为499的记录。所以Google查了下大致内容如下:

499 CLIENT CLOSED REQUEST A non-standard status code introduced by nginx for the case when a client closes the connection while nginx is processing the request. 链接:https://httpstatuses.com/499

大概意思就是nginx还在处理请求的时候客户端已经关闭了连接。

下面来简单模拟下这种情况

  • 新建test.php放在web根目录下,代码如下
<?php
sleep(20);//sleep20秒
echo 'ok';
  • 进行curl请求,超时时间和数据传输时间都设置为10秒
curl --connect-timeout 10 -m 10 http://localhost/test.php
  • nginx日志如下
127.0.0.1 - - [24/Jun/2017:23:11:23 +0800] "GET /test.php HTTP/1.1" 499 0 -  "-" "curl/7.51.0" "-"

以上可以看见http code 为499,并且客户端已经连接关闭了,没有接收到任何数据。

如果curl不设置超时时间进行请求的话就正常了。

curl http://localhost/test.php
会返回ok
同时nginx日志为
127.0.0.1 - - [24/Jun/2017:23:13:01 +0800] "GET /test.php HTTP/1.1" 200 12 -  "-" "curl/7.51.0" "-"

解决方案

  • 客户端超时时间设置大一点,不要等服务端还没处理完就关闭连接。
  • 服务端代码及逻辑优化,减少执行时间。如果是比较耗时的操作业务容许的情况下可以改为异步去处理(具体如何调整还需看业务流程及具体场景)

mysql中存储emoji表情

在做移动应用时,会遇到ios或者android用户会在文本的区域输入emoji表情(如:??),如果不做一定处理,就会导致插入数据库异常。如下:

Incorrect string value: '\xF0\x9F\x99\x82" ...' for column 'Source'

这是因为emoji表情符号为4个字节的字符,而 utf8 字符集只支持1-3个字节的字符,导致无法写入数据库。

解决方案:

1.修改数据库的字符集为utf8mb4。(注意:mysql版本需要5.5.3以上)具体是需要修改整个mysql库、表或者具体字段字符集自己决定。当然,修改完数据库字符集后还没有大功告成。需要看下程序里连接数据库的时候有没有指定字符集为utf8mb4。php中PDO连接方式如下:

$db = new pdo('mysql:host=127.0.0.1;port=3306;dbname=mysql;charset=utf8mb4','user','password');

2.如果不想修改数据库字符集或者版本比较低不支持,那就只能存的时候转义一下了。可以转为base64格式或者其他支持的转义方式。

 

如何做到高效的会议?

不管是在大公司还是一些中小型公司,除了日常工作,还有一项工作元素,那就是会议了。一场好的会议,可以让我们对过去发现的事情得出结论,对未来可能发生的问题有所预见,在团队建设方面,也有助于管理者了解团队成员的工作状态、工作态度以及工作问题。但是我们常有发生的情况是这样的:一场会议下来,三四个小时,结果毫无重点毫无决策,反而白白浪费了好多时间。

我觉得高效的会议大致应该做到以下几点:

  • 参加的人尽可能少,少到只需要对面沟通。不要动不动就拉上一批不相干的人进行开会。
  • 会议的时间要把控好,长时间的扯淡,断断续续、拖拖拉拉的浪费参与者时间。
  • 每次开会都必须有中心思想且做出一个明确的决定。
  • 尽量少开会。有问题当面沟通。不要开会成瘾。

以上仅为个人观点。

mongodb保存长整型的问题

最近用php往mongodb里面写数据的时候出现了一点小问题。就是毫秒级的时间戳保存到mongodb里面后数字被截断了。
例如:1439539213873保存后在mongo里显示为:725169713,这个不是我们想要的结果。

php代码:

$mongo = new MongoClient('mongodb://127.0.0.1:27017');
$db = $mongo->selectCollection("local", "test_data");
$data['num'] = 1439539213873;
$res = $db->insert($data);

mongo里结果:

> db.test_data.find();
{ "_id" : ObjectId("56b3036931a08a07628b4567"), "num" : 725169713 }
> 

 

解决方案:

1.查看php中mongo扩展的配置mongo.native_long,如果是0那在php.ini配置里面改为1;

2.对长整型的数字进行转换

$mongo = new MongoClient('mongodb://127.0.0.1:27017');
$db = $mongo->selectCollection("local", "test_data");
//$data['num'] = 1439539213873;
$data['num'] = new MongoInt64('1439539213873');//进行转换
$res = $db->insert($data);

mongo里结果:

> db.test_data.find();
{ "_id" : ObjectId("56b306c431a08ac80f8b4567"), "num" : NumberLong("1439539213873") }
> 

这样长的整型数字就不会被截断了。

记一次php curl给java提交数据失败的经历

最近由于业务需求需要对接一个对外接口(对方为java),简单来说就是需要通过post方式来给对方提交数据。但是对方一直收不到数据。简化代码如下:

$url = 'http://www.test.com';
$data = array(
  'name' => 'test',
  'age' => 123,
); 
$curl = curl_init (); // 启动一个CURL会话
curl_setopt ( $curl, CURLOPT_URL, $url ); // 要访问的地址
curl_setopt ( $curl, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt ( $curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
$result = curl_exec ( $curl ); // 执行操作
curl_close ( $curl ); 

后来发现是由于提交数据时header头的content-type跟对方不一致所导致。

  • CURLOPT_POSTFIELDS 这个参数字段数据为一个数组时,Content-Type头将会被设置成multipart/form-data(数据格式);
  • 而这个参数字符串类似’para1=val1&para2=val2&…’时,Content-Type头将会被设置成application/x-www-form-urlencoded(表单格式),就像表单提交的一样。

对方接收的Content-Type为application/x-www-form-urlencoded(表单格式),而现在PHP curl post提交数据时Content-Type为multipart/form-data(数据格式)。这才导致对方无法通过POST来接收数据。现在只需要把代码中

curl_setopt ( $curl, CURLOPT_POSTFIELDS, $data);
//更改为
curl_setopt ( $curl, CURLOPT_POSTFIELDS, http_build_query($data));

就OK了。

在PHP中通过POST方式接收的普通数据直接用$_POST就可以获取到,而如果是二进制流数据需要用$_FILES来获取。如果接收的数据是二进制流数据(文件)还用$_POST来接收,那只获取到的是这个文件的路径名字符串。

另外通过PHP的curl要发送文件,在文件名前面加上@前缀并使用完整路径就可以了。例如:

//$data['file']就是要发送的文件

$ch = curl_init();
$data = array('name' => 'Foo', 'file' => '@/home/user/test.png');
curl_setopt($ch, CURLOPT_URL, 'http://localhost/upload.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_exec($ch);