首页 技术PHP正文

php使用curl获取elasticsearch中数据

薄洪涛 PHP 2020-01-14 618 0 Elasticsearch

我最近在做一个电动车的项目,其中,有一个功能是这样的,我需要获取指定车辆的最新的五条位置信息,位置信息是保存到es库中的,我使用的是Yii2.0框架,本来想使用Yii封装的组件去获取数据的,然后觉得麻烦,就使用了curl调接口的形式

开始的时候,我是这么写的

function httpPost($server_url, $param) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $server_url); //地址
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_POST, 1); //post数据提交
    curl_setopt($ch, CURLOPT_POSTFIELDS, $param); //数据
    $body = curl_exec($ch);
    curl_close($ch);
    return $body;
}
//$post_data是我查询的语句
httpPost($es_search_url,json_encode($post_data));

然后会报这个错误

{"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406}

对了,我想起了来我应该设置下header头,修改如下

function httpPost($header, $server_url, $param) {
    $ch = curl_init();
    if($header){
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    }
    curl_setopt($ch, CURLOPT_URL, $server_url); //地址
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_POST, 1); //post数据提交
    curl_setopt($ch, CURLOPT_POSTFIELDS, $param); //数据
    $body = curl_exec($ch);
    curl_close($ch);
    return $body;
}
$rs_array = httpPost(["content-Type"=>"application/json"],$es_search_url,json_encode($post_data));

同时指定header为content-Type:application/json

没想到的是,没卵用,还是报上面的错误,然后我改成了这样

function http_post_json($url, $jsonStr)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonStr);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json; charset=utf-8',
            'Content-Length: ' . strlen($jsonStr)
        )
    );
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    return array($httpCode, $response);
}

看到没,需要加一个conent-length,原因是就是,es库对header头有严格的限制,官方解释如下

We know that the content-type sniffing has been quite convenient when using basic HTTP tools such as curl. Many of us are quite accustomed to searching a cluster by running something like this:

curl 'http://localhost:9200/_search' -d'
{
    "query" : {
        "match_all" : {}
    }
}'

But, we need to make that sort of operation slightly more verbose, and include the content-type, in the interests of clarity and security.

As Elasticsearch has evolved we’ve made a conscious decision to favour reliability and predictability over leniency. And while being lenient with content-types has been convenient, it also produced some surprising results.

For example, if you tried to send plain text content to an API that didn’t support it, then you would usually receive a clear error like this:

Content-Type header [text/plain] is not supported

But under the covers Elasticsearch was doing its best to try and guess what you might have meant. So, if your body started with “{” then it would guess that your content was actually JSON, but when it tried to parse that, it would fail and the error message would look more like:

Unexpected character ('a' (code 97)): was expecting double-quote to start field name

And, while most of our APIs support YAML formatted requests, the content-type sniffing required that the body start with a start-of-document marker (“---”), which is not what users expected.

When it comes to content-type, we’ve come to the conclusion that “Say what you mean” provides a more reliable and predictable outcome, than guessing. Being explicit is the safer, clearer and more consistent approach.



版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

评论