# http\_util

## http\_util

* [1 使用](#1-使用)
  * [1.1 常规使用](#11-常规使用)
  * [1.2 替换 requests 使用](#12-替换-requests-使用)
    * [1.2.1 requests](#121-requests)
    * [1.2.2 http\_util](#122-http_util)
* [2 常见问题](#2-常见问题)
  * [2.1 Unicode 解码错误](#21-unicode-解码错误)

## 1 使用

### 1.1 常规使用

> GET 请求，无参数

```
from xlib.util import http_util

res = http_util.get("http://127.0.0.1:8585/x/ping")
if res.success():
    print(res.output())
```

> GET 请求，校验结果，校验失败时会记录日志

```
from xlib.util import http_util

res = http_util.get("http://127.0.0.1:8585/x/ping", check_key="stat", check_value=0)
assert res.success() == False

res = http_util.get("http://127.0.0.1:8585/x/ping", check_key="stat", check_value="OK")
assert res.success() == True
print res.output()
```

> GET 请求, 有参数

```
http_util.get("http://127.0.0.1:8585/x/hello", params={"str_info": "meetbill"})
```

> post 请求，使用 JSON 方式

```
http_util.post_json("http://127.0.0.1:8585/x/hello", data={"str_info": "meetbill"}, debug=True)
```

> post 请求，使用 FORM 方式（butterfly 服务端不支持此方式）

```
print("[POST], post form---------------------------------[exe error]")
post_form("http://127.0.0.1:8585/x/hello", data={"str_info": "meetbill"}, debug=True)
```

> GET 请求, 有 header

```
# GET，have headers
headers = {"X_USERNAME": "meetbill"}
res = get("http://127.0.0.1:8585/demo_api/ping", headers=headers, debug=True)
if res.success():
    print(res.output())
```

### 1.2 替换 requests 使用

#### 1.2.1 requests

> 依赖包

```
requests-2.22.0.tar.gz
urllib3_1_26_2-1.26.2.0.tar.gz
idna-2.8.tar.gz
chardet-3.0.4.tar.gz
certifi-2019.6.16.tar.gz
```

> 代码

```
import requests

def main():
    ...
    r = requests.request(method, url, headers=headers, params=params, data=data, json=json, timeout=timeout)
    curl_cmd = http_util.to_curl_for_requests(r.request)
    logger.info(("cmd={cmd}\t"
                 "status_code={status_code}\t"
                 "response={response}".format(cmd=curl_cmd, status_code=r.status_code, response=r.text)))
    return res

-----
r.status_code : 响应状态码
r.json()      : JSON 响应内容
```

#### 1.2.2 http\_util

```
from xlib.util import http_util

def main():
    ...
    rsp = http_util.request(method, url, headers=headers, params=params, data=data, json=json, timeout=timeout)
    return rsp

-----
rsp.status_code : 响应状态码
rsp.json()      : JSON 响应内容
```

#### 1.2.3 SDK 装饰器

<pre><code>from xlib.util import wrapt
from xlib.util import funcsigs
from xlib.util import http_util
from xlib.util import config_util

<strong>def requested(method, uri):
</strong>    """
    添加 endpoint
    """
    @wrapt.decorator
    def wrapper(wrapped, instance, args, kwargs):
        """
        wrapper
        """
        # 提取原 func 中的 req, 不论使用位置参数还是关键字参数
        sig = funcsigs.signature(wrapped)
        kargs = dict(zip([k for k in sig.parameters if k not in kwargs], args))
        req = kargs.get("req", kwargs.get("req"))

        _service_name = "vm_manager"
        host = config_util.get_config(req, _service_name, "host")
        port = config_util.get_config(req, _service_name, "port")
        url = "http://{}:{}{}".format(host, port, uri)

        kwargs["method"] = method
        kwargs["url"] = url
        return wrapped(*args, **kwargs)
    return wrapper
    
------------------------------------------------------example
@requested(method="POST",
           uri="/v1/x1Resouce/instance/delete"
           )
def resource_delete(req, resource_id, **kwargs):
    """
    resource delete
    """
    data = {
        "instanceIds": [
            resource_id
        ],
        "userId": ""
    }
    headers = {"x_username": "x1_cli"}
    r = http_util.request(headers=headers, json=data, **kwargs)
    return r
</code></pre>

## 2 常见问题

### 2.1 Unicode 解码错误

> 错误信息

```
File "py_menu.py", line 46, in main
    self.first_menu()
  File "py_menu.py", line 102, in first_menu
    self.secondary_menu()
  File "py_menu.py", line 132, in secondary_menu
    fun[1](self.screen, **func_kargs)
  File "/home/work/chunfeng/sinan_cli_bak/three_page.py", line 65, in select_node
    return _exe_command(screen, service, offsets, action)
  File "/home/work/chunfeng/sinan_cli_bak/three_page.py", line 31, in _exe_command
    res = http_util.post_json("http://{ip}:5000/sinan/operation".format(ip=nodes[int(offset)]["ip"]), data=data)
  File "/home/work/chunfeng/sinan_cli_bak/w_lib/http_util.py", line 99, in post_json
    return RequestTool(url, **kwargs)
  File "/home/work/chunfeng/sinan_cli_bak/w_lib/http_util.py", line 297, in __init__
    res_attr=json.dumps(self.header)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 12: ordinal not in range(128)
```

> 程序中添加如下配置

```
import sys
reload(sys)
sys.setdefaultencoding('utf8')
```

> 异常原因

```
ERROR: 12-20 13:43:40: http_util.py:303 * 140336365434624 [file=/home/work/chunfeng/sinan_cli/three_page.py:_exe_command:31 type=http_POST req_path=http://xx.xx.xx.xx:5000/sinan/operation req_data={'action': 'status', 'service': 'redis_proxy', 'offset': 2} cost=0.000272 is_success=False err_no=-1 err_msg=[Errno 111] 拒绝连接 res_len=0 res_data= res_attr={}]

err_msg 中含有中文
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://meetbill.gitbook.io/butterfly-user-doc/tools/utility/http_util.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
