发送带有curl扩展名的HTTP / 2请求


卷曲建立选项

如果系统上安装的curl版本为7.3.3或更高版本,并且系统上安装的nghttp2为0.6.0或更高版本,并且将--with-nghttp2=PATH指定为构建选项,例如,可以使用HTTP / 2与PHP的curl扩展。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
./configure --prefix=`pwd`/local --with-nghttp2

curl version:     7.42.0-DEV
Host setup:       x86_64-apple-darwin14.1.0
Install prefix:   /Users/masakielastic/test/curl/local
Compiler:         gcc
SSL support:      enabled (OpenSSL)
SSH support:      no      (--with-libssh2)
zlib support:     enabled
GSS-API support:  no      (--with-gssapi)
TLS-SRP support:  no      (--enable-tls-srp)
resolver:         default (--enable-ares / --enable-threaded-resolver)
IPv6 support:     enabled
Unix sockets support: enabled
IDN support:      enabled
Build libcurl:    Shared=yes, Static=yes
Built-in manual:  enabled
--libcurl option: enabled (--disable-libcurl-option)
Verbose errors:   enabled (--disable-verbose)
SSPI support:     no      (--enable-sspi)
ca cert bundle:   no
ca cert path:     no
LDAP support:     enabled (OpenLDAP)
LDAPS support:    enabled
RTSP support:     enabled
RTMP support:     no      (--with-librtmp)
metalink support: no      (--with-libmetalink)
HTTP2 support:    enabled (nghttp2)
Protocols:        DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS LDAP LDAPS POP3 POP3S RTSP SMB SMBS SMTP SMTPS TELNET TFTP

您可以运行

curl -V来查看nghttp2 build选项是否有效。

1
2
3
curl 7.41.0 (x86_64-apple-darwin14.1.0) libcurl/7.41.0 OpenSSL/1.0.2a zlib/1.2.5 nghttp2/0.7.7
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets

由curl命令请求

执行以下命令并目视检查响应。

1
curl --http2 -v https://http2bin.org/get

您也只能输出

标头。

1
curl -I --http2 https://http2bin.org/get

结果如下。确保包含" HTTP / 2.0 200"。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
*   Trying 104.131.161.90...
* Connected to http2bin.org (104.131.161.90) port 443 (#0)
* ALPN, offering h2-14, http/1.1
* successfully set certificate verify locations:
*   CAfile: /usr/local/etc/openssl/cert.pem
  CApath: none
* NPN, negotiated HTTP2 (h2-14)
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*    subject: OU=Domain Control Validated; OU=EssentialSSL; CN=www.http2bin.org
*    start date: 2015-02-21 00:00:00 GMT
*    expire date: 2016-02-21 23:59:59 GMT
*    issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Domain Validation Secure Server CA
*    SSL certificate verify ok.
* Using HTTP2
* http2_send len=54
* before_frame_send() was called
* on_frame_send() was called
* before_frame_send() was called
* on_frame_send() was called
> GET /get HTTP/1.1
Host: http2bin.org
Accept: */*

* http2_recv: 16384 bytes buffer
* nread=27
* on_frame_recv() was called with header 4
* nghttp2_session_mem_recv() returns 27
* before_frame_send() was called
* on_frame_send() was called
* http2_recv: 16384 bytes buffer
* nread=9
* on_frame_recv() was called with header 4
* nghttp2_session_mem_recv() returns 9
* http2_recv: 16384 bytes buffer
* nread=345
* on_begin_headers() was called
* got http2 header: server: h2o/1.1.1
* got http2 header: date: Mon, 16 Mar 2015 21:47:58 GMT
* got http2 header: content-type: application/json
* got http2 header: access-control-allow-origin: *
* got http2 header: access-control-allow-credentials: true
* got http2 header: x-clacks-overhead: GNU Terry Pratchett
* on_frame_recv() was called with header 1
* on_data_chunk_recv() len = 218, stream = 1
* 218 data written
* on_frame_recv() was called with header 0
* on_stream_close() was called, error_code = 0
* nghttp2_session_mem_recv() returns 345
< HTTP/2.0 200
< server:h2o/1.1.1
< date:Mon, 16 Mar 2015 21:47:58 GMT
< content-type:application/json
< access-control-allow-origin:*
< access-control-allow-credentials:true
< x-clacks-overhead:GNU Terry Pratchett
<
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Connection": "keep-alive",
    "Host": "http2bin.org",
    "Via": "2 http2bin.org"
  },
  "origin": "106.184.75.63",
  "url": "https://http2bin.org/get"
}
* Connection #0 to host http2bin.org left intact

安装

家酿

确保事先拥有最新的OpenSSL。如果不运行brew link命令,则将使用Mac OS X上安装的默认OpenSSL。

1
2
3
4
brew update
brew install openssl
brew link openssl --force
openssl version

安装

curl时,将--with-nghttp2指定为构建选项。

1
2
brew install curl --with-nghttp2 --with-openssl
brew link curl --force

我有自己的公式,因为以前的官方公式中没有构建选项,因此我想尝试最新版本。您可以使用以下命令进行安装。

1
2
3
brew update
brew install masakielastic/http2/curl --with-openssl
brew link curl --force

linuxbrew

如果要在主要Linux发行版的个人目录中安装并尝试curl,则软件包管理工具linuxbrew很有用。 linuxbrew是Mac OSX上启用Linux的homebrew版本。当我将其介绍给Ubunutu时,我必须安装以下附加软件包。

1
sudo apt-get install pkg-conf python-setuptools

以下命令将安装curl。

1
brew install curl --with-nghttp2

Ubuntu 16.04 LTS

您可以通过重新编译使用HTTP / 2。启动板上提供了说明。

首先安装nghttp2和构建所需的工具。

1
2
sudo apt install libnghttp2-dev
sudo apt build-dep curl

接下来,下载源代码。

1
2
apt source curl
cd curl-7.47.0

编辑

debian / control并在Build-Depends部分中添加libnghttp2-dev。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Build-Depends: debhelper (>= 9),
 autoconf,
 automake,
 ca-certificates,
 groff-base,
 libgnutls-dev,
 libidn11-dev,
 libkrb5-dev,
 libldap2-dev,
 libnss3-dev,
 librtmp-dev (>= 2.4+20131018.git79459a2-3~),
 libssl-dev,
 libnghttp2-dev,
...

构建并安装。测试将花费5到10分钟。

1
2
sudo debian/rules binary
sudo dpkg -i ../*deb

CURL_HTTP_VERSION_2_0

的定义

发送

HTTP / 2请求所需要做的就是将CURL_HTTP_VERSION_2_0指定为与CURLOPT_HTTP_VERSION相对应的值。从PHP 5.6.8和5.5.24系列开始可用。早期版本要求您自己定义CURL_HTTP_VERSION_2_0

1
2
3
if (!defined('CURL_HTTP_VERSION_2_0')) {
    define('CURL_HTTP_VERSION_2_0', CURL_HTTP_VERSION_1_1 + 1);
}

curl/curl.h中,CURL_HTTP_VERSION_2_0由枚举定义如下。

1
2
3
4
5
6
7
8
9
10
enum {
  CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
                             like the library to choose the best possible
                             for us! */
  CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
  CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
  CURL_HTTP_VERSION_2_0,  /* please use HTTP 2.0 in the request */

  CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
};

卷曲延伸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (!defined('CURL_HTTP_VERSION_2_0')) {
    define('CURL_HTTP_VERSION_2_0', CURL_HTTP_VERSION_1_1 + 1);
}

$url = 'https://http2bin.org/get';

$opts = [
    CURLOPT_VERBOSE => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_SSL_VERIFYPEER => false
];

$ch = curl_init($url);
curl_setopt_array($ch, $opts);
curl_exec($ch);
curl_close($ch);

枪口

对于版本5。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use GuzzleHttp\Client;

if (!defined('CURL_HTTP_VERSION_2_0')) {
    define('CURL_HTTP_VERSION_2_0', CURL_HTTP_VERSION_1_1 + 1);
}

$client = new Client();
$client
  ->get(
    'https://http2bin.org/get', [
    'future' => true,
    'config' => [
        'curl' => [
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0
        ]
    ],
    'debug' => true
    ]
  )
  ->then(function($response) {
    var_dump(
      $response->getStatusCode(),
      $response->getHeader('Content-Type'),
      (string) $response->getBody()
    );
  });

戒指PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use GuzzleHttp\Ring\Client\CurlHandler;

if (!defined('CURL_HTTP_VERSION_2_0')) {
    define('CURL_HTTP_VERSION_2_0', CURL_HTTP_VERSION_1_1 + 1);
}

$handler = new CurlHandler();
$response = $handler([
    'http_method' => 'GET',
    'scheme'      => 'https',
    'uri'         => '/get',
    'headers' => [
        'host' => ['http2bin.org']
    ],
    'client' => [
        'curl' => [
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0
        ],
        'debug' => true
    ]
]);

$response->then(function (array $response) {
    var_dump($response);
});

如何确定HTTP / 2是否可用

如果要根据HTTP / 2的可用性更改curl选项的配置,请使用curl_version

1
2
3
4
5
6
7
8
9
if (!defined('CURL_VERSION_HTTP2')) {
    define('CURL_VERSION_HTTP2', 1<<16);
}

if (curl_version()['features'] & CURL_VERSION_HTTP2) {
    echo "HTTP/2 は利用できます。\n";
} else {
    echo "HTTP/2 は利用できません。\n";
}

CURL_VERSION_HTTP2在curl / curl.h中定义。

1
2
3
4
#define CURL_VERSION_HTTP2        (1<<16) /* HTTP2 support built-in */
#define CURL_VERSION_GSSAPI       (1<<17) /* Built against a GSS-API library */
#define CURL_VERSION_KERBEROS5    (1<<18) /* Kerberos V5 auth is supported */
#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */

使用HTTP / 2兼容服务器

h2o

h2o从版本1.3开始支持php-fpm。在Mac OS X上,您可以使用自制软件安装并启动它。配置文件路径为/usr/local/etc/h2o/h2o.conf,端口号为8080

1
2
3
brew install h2o
ln -sfv /usr/local/opt/h2o/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.h2o.plist

h2o.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
file.custom-handler:
  extension: .php
  fastcgi.connect:
    host: 127.0.0.1
    port: 9000
    type: tcp
listen:
  port: 8080
  ssl:
    certificate-file: /path/to/server.crt
    key-file: /path/to/server.key
hosts:
  "127.0.0.1.xip.io:8080":
    paths:
      /:
        file.dir: /usr/local/var/h2o/

使用Ubuntu的php-fpm时,必须以Unix套接字格式编写。

1
2
3
4
5
file.custom-handler:
  extension: .php
  fastcgi.connect:
    port: /var/run/php5-fpm.sock
    type: unix

如果您需要预安装在系统上的php-fpm之外的Fast CGI程序来试用PHP的开发版本,则可以让h2o为您创建和管理它。我在Ubuntu上检查了以下设置。

1
2
3
4
5
file.custom-handler:
  extension: .php
  fastcgi.spawn:
    command: "PHP_FCGI_CHILDREN=10 exec /usr/bin/php-cgi"
    user: nobody

nginx

Nginx从1.9.5开始可用。从源代码构建时,请指定--with-http_v2_module选项。对于Debian / Ubuntu,可以使用nginx.org存储库。将与以下类似的代码添加到/etc/apt/sources.list

1
2
deb http://nginx.org/packages/ubuntu/ trusty nginx
deb-src http://nginx.org/packages/ubuntu/ trusty nginx

监听指令中指定。

1
2
3
4
5
6
7
8
server {
    listen 443 ssl http2 default_server;

    ssl_certificate    server.crt;
    ssl_certificate_key server.key;

    #...
}

的Apache

mod_http2模块现在在Apache 2.4.17中可用。指定--enable-http2作为构建选项。对于Ubuntu,PPA是可用的。

1
sudo add-apt-repository -y ppa:ondrej/apache2

将Protocols指令添加到配置文件。

1
2
3
4
5
# /etc/apache2/sites-available/000-default.conf
Protocols h2c http/1.1

# /etc/apache2/sites-available/default-ssl.conf
Protocols h2 http/1.1

反向代理

的HTTP / 2支持

让我们在端口号80上建立HTTP1服务器,并使HTTP2客户端可以从端口号8080访问它。

nghttpx

如果

nghttpx,请执行以下命令。假定已预先准备好SSL / TLS证书。

1
nghttpx -f0.0.0.0,8080 -b127.0.0.1,80 server.key server.crt

h2o

对于

h2o,请准备以下配置文件。

proxy.conf

1
2
3
4
5
6
7
8
9
10
11
listen:
  port: 8080
  ssl:
    certificate-file: examples/h2o/server.crt
    key-file: examples/h2o/server.key
hosts:
   default:
    paths:
      /:
        proxy.reverse.url: http://127.0.0.1:80/
    access-log: /dev/stdout

让我们开始

h2o

1
h2o -c proxy.conf

CDN服务

CloudFlare支持HTTP / 2,并且可以与共享托管服务一起使用,这些服务不允许您配置自己的SSL / TLS。我已经确认使用WebCrow的免费计划进行HTTP / 2通信(参考文章)。

在2016年4月增加了对服务器推送的支持。您可以在博客文章中找到PHP的示例代码。

共享主机服务

截至2016年5月,日本公司不支持它。棒棒糖已经宣布未来的支持。在海外,支持A2托管和SiteGround。