> For the complete documentation index, see [llms.txt](https://meetbill.gitbook.io/butterfly-user-doc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://meetbill.gitbook.io/butterfly-user-doc/tools/utility/http_util.md).

# 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 中含有中文
```
