最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 使用curl发网络请求

    正文概述 掘金(挖掘机F)   2021-02-24   691

    前端离不开网络请求,那有哪些方式可以发送请求呢?首先,在代码中使用XHR和fetch、构造Img等都是比较常用的手段,开发者工具也提供了重发请求的功能用于调试;类库方面,axios,request,node-fetch等都能做得很好,特别是axios,在日常工作中经常用到;另外,一些调试工具如fiddler、whistle等都有composer功能,可以用于构造并发送请求,postman则是专门的客户端请求代理软件。除此之外,linux层面其实有一个原生的客户端请求软件 —— curl(client URL)。

    curl可以支持SMTP, FTP, POP3, HTTP, HTTPS等多种协议,我们在此只讨论HTTP家族的协议。

    为了测试curl发送的请求头和请求体,可以在本地启动一个回声服务,原样发回请求报文文本:

    const http = require('http');
    
    const server = http.createServer((req, res) => {
      res.setHeader('set-cookie', 'mycookie=1234567');
      res.write(`
    from port: ${req.socket.remotePort}
    request method: ${req.method}
    request url: ${req.url}
    ${JSON.stringify(req.headers)}
      `);
      req.on('data', (chunk) => res.write(String(chunk)));
      req.on('end', () => res.end());
    });
    
    server.listen(3001, () => console.log('server running on port 3001'));
    

    简单用法

    使用curl发送一个get请求:curl localhost:3001可以得到返回结果:

    from port: 63574
    request method: GET
    request url: /
    {"host":"localhost:3001","user-agent":"curl/7.64.1","accept":"*/*"}
    

    可见发送的请求会默认带上host, user-agent, accept这几个请求头,那怎么增加请求头呢?可以用上下面这些选项:

    • -A --user-agent指定user-agent头字段
    • -b --cookie增加cookie字段,如果值以@开头则会找到对应的cookie文件读取cookie(cookie由服务器设置,可以保存在本地,详见下方"输出"相关的内容)
    • -e --referer携带referer头字段
    • -H --header添加/更改/删除头字段

    -H遵循下面的使用规则:

    # 添加/修改请求头
    --header "user-agent:myagent/super1.0"
    # 删除请求头
    --header "user-agent:" 
    # 增加空请求头
    --header "x-custom-header;"
    

    重定向

    有了上面的基础,让我们构造一个请求:curl -A "Mozilla/5.0 whatever" -i -H "X-my-option:000" www.qq.com(此处使用了-i打印出响应头), 可以在命令行得到如下输出结果:

    HTTP/1.1 302 Moved Temporarily
    Server: stgw/1.3.12.4_1.13.5
    Date: Sat, 14 Nov 2020 12:58:19 GMT
    Content-Type: text/html
    Content-Length: 169
    Connection: keep-alive
    Location: https://www.qq.com/
    
    <html>
    <head><title>302 Found</title></head>
    <body bgcolor="white">
    <center><h1>302 Found</h1></center>
    <hr><center>stgw/1.3.12.4_1.13.5</center>
    </body>
    </html>
    

    curl默认使用http协议进行请求,访问http://www.qq.com会返回一个302的重定向消息,但是curl默认并不会自动跟踪重定向指向的网络地址https://www.qq.com,此时可以添加-L --location选项开启自动跟踪重定向,但要注意的一点是,网络重定向可能形成环状跳转,比如urlA重定向到urlB,urlB再重定向回urlA,这种跳转会一直持续下去,造成资源的浪费,可以使用--max-redirs选项指定链接最大可跳转次数。

    加上重定向,再请求一次curl -A "Mozilla/5.0 whatever" -i -H "X-my-option:000" -L www.qq.com命令行打印如下,可见成功进行了跳转。

    HTTP/1.1 302 Moved Temporarily
    Server: stgw/1.3.12.4_1.13.5
    Date: Sat, 14 Nov 2020 13:01:56 GMT
    Content-Type: text/html
    Content-Length: 169
    Connection: keep-alive
    Location: https://www.qq.com/
    
    HTTP/2 200 
    date: Sat, 14 Nov 2020 13:01:56 GMT
    content-type: text/html; charset=GB2312
    server: squid/3.5.24
    vary: Accept-Encoding
    vary: Accept-Encoding
    expires: Sat, 14 Nov 2020 13:02:56 GMT
    cache-control: max-age=60
    x-cache: HIT from shenzhen.qq.com
    
    <...省略html文本>
    

    发送post请求

    上面讲的都是发送get请求,那怎么发post请求呢?curl中可以指定-d --data选项添加post数据,如:curl -d "name=可莉" --data "age=8" http://localhost:3001/, 命令行打印:

    from port: 64823
    request method: POST
    request url: /
    {"host":"localhost:3001","user-agent":"curl/7.64.1","accept":"*/*","content-length":"17","content-type":"application/x-www-form-urlencoded"}
    
      name=可莉&age=8
    

    可见data选项原封不动地发送了我们提供的数据,在数据条目之间添加了&,但一般post请求是需要对字符进行编码处理的,我们可以使用--data-urlencode选项代替--data,比如curl --data-urlencode "name=可莉" --data "age=8" http://localhost:3001/,请求体就会进行编码:

    from port: 65459
    request method: POST
    request url: /
    {"host":"localhost:3001","user-agent":"curl/7.64.1","accept":"*/*","content-length":"29","content-type":"application/x-www-form-urlencoded"}
    
      name=%E5%8F%AF%E8%8E%89&age=8
    

    如果想发送文件,就需要用到另外一个选项-F --form,开启这个选项curl使用内置的一个type为multipart/form-data的form表单模拟提交操作,如:curl -F name=romio -F profile=@myprofile http://localhost:3001/

    from port: 49288
    request method: POST
    request url: /
    {"host":"localhost:3001","user-agent":"curl/7.64.1","accept":"*/*","content-length":"356","content-type":"multipart/form-data; boundary=------------------------1db05266264c6354"}
    
      --------------------------1db05266264c6354
    Content-Disposition: form-data; name="name"
    
    romio
    --------------------------1db05266264c6354
    Content-Disposition: form-data; name="profile"; filename="myprofile"
    Content-Type: application/octet-stream
    
    ###oooo### <文本内容>
    ##o####o##
    #o##o#o#o#
    ##o####o##
    ###oooo###
    --------------------------1db05266264c6354--
    

    需要注意的一点是-d-F不能混用,原因是比较清晰的,-d选项发送的content-typeapplication/x-www-form-urlencoded, 与后者不同。

    输出

    如何把返回结果保存为文件呢?

    • -o --output指定输出文件地址,指定为-输出到标准输出
    • -O解析目标url,自动命名保存,如http://a.c.com/a.html保存为a.html
    • --create-dirs 如果输出文件的路径不存在则创建
    • -c --cookie-jar 存储服务端返回的cookie, 指定为-输出到标准输出
    • -D --dump-header 指定存储响应头的文件

    比如使用curl -o file -c baiducookie -b @baiducookie http://www.baidu.com, 则请求对应地址并保存到file文件,cookie保存到baiducookie文件。

    指定输出格式

    有时并不需要获取对应url对应的文本内容,只需要获取状态码、content-type等信息,这需要指定-w --write-out选项,该选项使用一个格式化字符串作为参数,如curl -w '%{http_code} %{content_type}' www.baidu.com 输出的末尾将打印200 text/html,进一步,我们可以定义一个检测url是否可达的bash函数:

    is_url_reachable() {
      local RET_CODE=$(curl -o /dev/null -IsfLw '%{http_code}\n' --max-time 3 "$1" 2>&1)
      if [ -n "$RET_CODE" ] && [ $(echo $RET_CODE | cut -c 1-1) = "2" ]; then
        return 0
      else
        return 1
      fi
    }
    

    配置

    超时和重试

    • limit-rate 参数是/\d+[KMG]/i的形式,可以限制网络速度为多少K/M/G每秒
    • --connect-timeout 指定超时时间(s)
    • -m --max-time 指定最大持续时间(s),包含此命令执行所有阶段的时间
    • --retry 重试次数
    • --retry-delay 重试时间间隔(s)

    代理

    • --proxy-header 为代理添加请求头
    • -p --proxy 指定代理

    如给请求添加代理:curl -p 8.8.8.8 www.baidu.com

    请求方式

    • -G --get 置换请求方式为get
    • -I --head 置换请求方式为head

    当请求中添加-d之后,curl默认发post请求,可以添加-G-H将请求类型置换为get请求,c此时-d中的内容会以?<params>的形式附加到url中,如curl -G --data-url "name=可莉" -d age=8 localhost:3001打印结果是:

    from port: 50660
    request method: GET
    request url: /?name=%E5%8F%AF%E8%8E%89&age=8
    {"host":"localhost:3001","user-agent":"curl/7.64.1","accept":"*/*"}
    

    输出控制

    这里的选项一般用在bash脚本文件中,可以更好地控制curl的输出。

    • -# --progress-bar显示进度条
    • -f --fail 如果服务端错误则静默失败,并返回error code 22
    • --fail-early 一般curl都是顺序请求给定的url,并返回最后一个请求的错误码,开启这个选项可以在curl失败后立即返回
    • -s --silent 不显示错误信息和进度条, 一般配合-S --show-error使用,使用这个选项会显示错误信息
    • -v --verbose显示通信细节

    配置文件

    使用-K --config <filename>可以指定一个文件作为curl的配置文件,该配置文件每一行描述一条规则,使用url=<request_url>指定请求的url地址,格式如下:

    # curlfile
    # 指定请求地址
    url=http://www.baidu.com
    # 开启重定向
    location
    # 设置user-agent请求头
    user-agent="Mozilla/5.0 whatever"
    # cookie文件
    cookie=@baiducookie
    # 保存cookie的文件
    cookie-jar=baiducookie
    # 最大请求时间
    max-time=10
    # 请求速度
    limit-rate=80K
    # 显示进度条
    progress-bar
    # 输出
    output=/dev/null
    

    可以在同一个文件中描述多条请求,描述下一条请求需要使用-: --next选项,上一条请求中指定的选项将重置,比如在上面的文件后面增加如下内容,即可发送两次请求:

    # --------------------------- #
    # the next request
    
    next
    
    url="http://localhost:3001/"
    

    从控制台的打印结果看,两个请求是串行发送的,即先发送第一个请求,然后发送第二个,curl默认进行串行请求,添加-Z --parallel之后可以并行请求(7.66.0版本开始支持,查看版本curl --version)。如果curl版本不支持,可以使用类似下面的操作代替:

    echo "-A \"Mozilla/5.0 whatever\" -b @baiducookie -L --limit-rate 20k -o /dev/null www.baidu.com \n -o /dev/null --limit-rate 20k -L www.qq.com" | xargs -L 1 -P 2 curl
    

    调试

    使用--trace <file>选项可以开启网络调试,它会将请求过程中传输的二进制数据、数据的描述、请求阶段描述等信息保存为文件,也可以指定file为-输出到标准输出。

    如使用curl --trace tracefile --location www.qq.com,网络请求信息会被保存到tracefile中,从其中可以清晰地分辨出请求头、请求体、重定向、TLS握手等信息:

    == Info:   Trying 61.241.49.173...
    == Info: TCP_NODELAY set
    == Info: Connected to www.qq.com (127.0.0.1) port 80 (#0)
    => Send header, 74 bytes (0x4a) # 请求头
    0000: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1..
    0010: 48 6f 73 74 3a 20 77 77 77 2e 71 71 2e 63 6f 6d Host: www.qq.com
    0020: 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 63 75 ..User-Agent: cu
    0030: 72 6c 2f 37 2e 36 34 2e 31 0d 0a 41 63 63 65 70 rl/7.64.1..Accep
    0040: 74 3a 20 2a 2f 2a 0d 0a 0d 0a                   t: */*....
    <= Recv header, 32 bytes (0x20) # 响应头
    0000: 48 54 54 50 2f 31 2e 31 20 33 30 32 20 4d 6f 76 HTTP/1.1 302 Mov
    0010: 65 64 20 54 65 6d 70 6f 72 61 72 69 6c 79 0d 0a ed Temporarily..
    <= Recv header, 30 bytes (0x1e)
    0000: 53 65 72 76 65 72 3a 20 73 74 67 77 2f 31 2e 33 Server: stgw/1.3
    0010: 2e 31 32 2e 34 5f ...
    <= Recv header, 2 bytes (0x2) # 响应头结束
    0000: 0d 0a                                           ..
    == Info: Ignoring the response-body
    <= Recv data, 169 bytes (0xa9) # 获取body
    0000: 3c 68 74 6d 6c 3e 0d 0a 3c 68 65 61 64 3e 3c 74 <html>..<head><t
    0010: 69 74 6c 65 3e 33 30 32 20 46 6f 75 6e 64 3c 2f itle>302 Found</
    0020: 74 69 74 6c 65 3e 3c 2f 68 65 61 64 3e 0d 0a 3c title></head>..<
    0030: 62 6f 64 79 20 62 67 63 6f 6c 6f 72 3d 22 77 68 body bgcolor="wh
    0040: 69 74 65 22 3e 0d 0a 3c 63 65 6e 74 65 72 3e 3c ite">..<center><
    0050: 68 31 3e 33 30 32 20 46 6f 75 6e 64 3c 2f 68 31 h1>302 Found</h1
    0060: 3e 3c 2f 63 65 6e 74 65 72 3e 0d 0a 3c 68 72 3e ></center>..<hr>
    0070: 3c 63 65 6e 74 65 72 3e 73 74 67 77 2f 31 2e 33 <center>stgw/1.3
    0080: 2e 31 32 2e 34 5f 31 2e 31 33 2e 35 3c 2f 63 65 .12.4_1.13.5</ce
    0090: 6e 74 65 72 3e 0d 0a 3c 2f 62 6f 64 79 3e 0d 0a nter>..</body>..
    00a0: 3c 2f 68 74 6d 6c 3e 0d 0a                      </html>..
    == Info: Connection #0 to host www.qq.com left intact
    == Info: Issue another request to this URL: 'https://www.qq.com/' # 重定向到这个链接
    == Info:   Trying 61.241.49.173...
    == Info: TCP_NODELAY set # TCP连接
    == Info: Connected to www.qq.com (127.0.0.1) port 443 (#1)
    == Info: ALPN, offering h2 # 应用层协议协商
    == Info: ALPN, offering http/1.1
    == Info: successfully set certificate verify locations: # 检查网站证书
    == Info:   CAfile: /etc/ssl/cert.pem 
      CApath: none
    # 下面是TLS握手的消息
    == Info: TLSv1.2 (OUT), TLS handshake, Client hello (1): # 客户端发送hello消息, 包含客户端支持的 TLS 版本、支持的密码套件,以及称为“客户端随机数”的一串随机字节。
    => Send SSL data, 224 bytes (0xe0)
    0000: 01 00 00 dc 03 03 e5 d8 07 6e ...
    == Info: TLSv1.2 (IN), TLS handshake, Server hello (2): # 服务端回复hello消息,内含服务器选择的密码套件,以及“服务器随机数”,即由服务器生成的另一串随机字节。
    <= Recv SSL data, 102 bytes (0x66)
    0000: 02 00 00 62 03 03 b7 41 b9 d7 ...
    == Info: TLSv1.2 (IN), TLS handshake, Certificate (11): # 服务端发送 SSL 证书
    <= Recv SSL data, 5882 bytes (0x16fa)
    0000: 0b 00 16 f6 00 16 f3 00 11 d3 30 82 11 cf 30 82 ..........0...0.
    0010: 10 b7 a0 03 02 01 02 02 10 07 88 51 f4 87 ...
    == Info: TLSv1.2 (IN), TLS handshake, Server key exchange (12): # 服务端发送经加密的算法公钥(Server Random),需要客户端用网站证书中的公钥解密
    <= Recv SSL data, 333 bytes (0x14d)
    0000: 0c 00 01 49 03 00 17 41 04 28 4a 76 3e ...
    == Info: TLSv1.2 (IN), TLS handshake, Server finished (14): # 服务端Hello完成
    <= Recv SSL data, 4 bytes (0x4)
    0000: 0e 00 00 00                                     ....
    == Info: TLSv1.2 (OUT), TLS handshake, Client key exchange (16): # 客户端发送经加密的算法公钥(Client Random),需要服务端使用客户端的公钥解密,之后服务端和客户端分别通过秘钥生成算法生成主秘钥和会话秘钥
    => Send SSL data, 70 bytes (0x46)
    0000: 10 00 00 42 41 04 b9 7c 5b 07 08 4c 49 ...
    == Info: TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): # 客户端之后使用会话秘钥(client_write_key)加密通信
    => Send SSL data, 1 bytes (0x1)
    0000: 01                                              .
    == Info: TLSv1.2 (OUT), TLS handshake, Finished (20): # 客户端握手成功
    => Send SSL data, 16 bytes (0x10)
    0000: 14 00 00 0c 08 0e f2 19 12 1b 47 ff df 4a 19 1d ..........G..J..
    == Info: TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): # 服务端之后使用会话秘钥(server_write_key)加密通信
    <= Recv SSL data, 1 bytes (0x1)
    0000: 01                                              .
    == Info: TLSv1.2 (IN), TLS handshake, Finished (20): # 服务端握手成功
    <= Recv SSL data, 16 bytes (0x10)
    0000: 14 00 00 0c b1 18 18 41 8a 46 9f e3 07 2c 16 99 .......A.F...,..
    # TLS握手成功,开始进行HTTP通信
    == Info: SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
    == Info: ALPN, server accepted to use h2
    == Info: Server certificate:
    == Info:  subject: C=CN; ST=Guangdong Province; L=Shenzhen; O=Shenzhen Tencent Computer Systems Company Limited; OU=R&D; CN=www.qq.com
    == Info:  start date: Jun 22 00:00:00 2020 GMT
    == Info:  expire date: Sep 22 12:00:00 2021 GMT
    == Info:  subjectAltName: host "www.qq.com" matched cert's "www.qq.com"
    == Info:  issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=Secure Site CA G2
    == Info:  SSL certificate verify ok.
    == Info: Using HTTP2, server supports multi-use
    == Info: Connection state changed (HTTP/2 confirmed)
    == Info: Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
    == Info: Using Stream ID: 1 (easy handle 0x7f93c800fc00)
    => Send header, 72 bytes (0x48) # 发送请求头
    0000: 47 45 54 20 2f 20 48 54 54 50 2f 32 0d 0a 48 6f GET / HTTP/2..Ho
    0010: 73 74 3a 20 77 77 77 2e 71 71 2e 63 6f 6d 0d 0a st: www.qq.com..
    0020: 55 73 65 72 2d 41 67 65 6e 74 3a 20 63 75 72 6c User-Agent: curl
    0030: 2f 37 2e 36 34 2e 31 0d 0a 41 63 63 65 70 74 3a /7.64.1..Accept:
    0040: 20 2a 2f 2a 0d 0a 0d 0a                          */*....
    == Info: Connection state changed (MAX_CONCURRENT_STREAMS == 128)! # 接收响应头和响应体
    <= Recv header, 13 bytes (0xd)
    0000: 48 54 54 50 2f 32 20 32 30 30 20 0d 0a          HTTP/2 200 ..
    <= Recv header, 37 bytes (0x25)
    0000: 64 61 74 65 3a 20 53 75 6e 2c 20 31 35 20 4e 6f date: Sun, 15 No
    0010: 76 20 32 30 32 ...
    

    总结

    本文分析了curl这个客户端请求软件的基础用法,它的功能还是很强大的,在诸如接口调试、调用机器人API、下载文件(推荐直接使用wget)等场合都可以发挥一些作用,写一个curl配置文件对定时任务也很有帮助,调试选项可以提供类似抓包工具的请求细节,对于分析、诊断网络请求有一定的作用。

    更多选项请查看在线文档。


    起源地下载网 » 使用curl发网络请求

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元