我举个例子,
首先决定你要模拟什么浏览器,在这种情况下我选择Firefox 60.6.1esr (64-bit),并检查它发出什么GET请求,这可以通过一个简单的netcat服务器获得(MacOS捆绑netcat,大多数Linux发行版捆绑netcat,Windows用户可以从.. Cygwin.org 等地方获取 netcat),
设置 netcat 服务器监听 9999 端口:nc -l 9999
现在在 Firefox 中点击 http://127.0.0.1:9999,我明白了:
$ nc -l 9999
GET / HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
现在让我们将其与这个简单的脚本进行比较:
<?php
$ch=curl_init("http://127.0.0.1:9999");
curl_exec($ch);
我明白了:
$ nc -l 9999
GET / HTTP/1.1
Host: 127.0.0.1:9999
Accept: */*
这里有几个缺少的标头,它们都可以使用 curl_setopt 的 CURLOPT_HTTPHEADER 选项添加,但 User-Agent 特别应该使用 CURLOPT_USERAGENT 设置(它将在多次调用 curl_exec() 时保持不变,如果您使用CURLOPT_FOLLOWLOCATION 那么它也将在 http 重定向中持续存在),并且应该使用 CURLOPT_ENCODING 设置 Accept-Encoding 标头(如果使用 CURLOPT_ENCODING 设置它们,那么如果服务器选择压缩它,curl 将自动解压缩响应,但是如果您通过 CURLOPT_HTTPHEADER 设置它,那么你必须自己手动检测和解压缩内容,这很麻烦而且完全没有必要,一般来说)所以添加我们得到的内容:
<?php
$ch=curl_init("http://127.0.0.1:9999");
curl_setopt_array($ch,array(
CURLOPT_USERAGENT=>'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0',
CURLOPT_ENCODING=>'gzip, deflate',
CURLOPT_HTTPHEADER=>array(
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language: en-US,en;q=0.5',
'Connection: keep-alive',
'Upgrade-Insecure-Requests: 1',
),
));
curl_exec($ch);
现在运行该代码,我们的 netcat 服务器得到:
$ nc -l 9999
GET / HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Upgrade-Insecure-Requests: 1
瞧!我们的 php 模拟 browser GET 请求现在应该与真正的 firefox GET 请求没有区别了:)
下一部分只是吹毛求疵,但如果你仔细观察,你会发现标头以错误的顺序堆叠,firefox 将 Accept-Encoding 标头放在第 6 行,我们模拟的 GET 请求将其放入第 3 行.. 要解决这个问题,我们可以手动将 Accept-Encoding 标头放在正确的行中,
<?php
$ch=curl_init("http://127.0.0.1:9999");
curl_setopt_array($ch,array(
CURLOPT_USERAGENT=>'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0',
CURLOPT_ENCODING=>'gzip, deflate',
CURLOPT_HTTPHEADER=>array(
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language: en-US,en;q=0.5',
'Accept-Encoding: gzip, deflate',
'Connection: keep-alive',
'Upgrade-Insecure-Requests: 1',
),
));
curl_exec($ch);
运行它,我们的 netcat 服务器得到:
$ nc -l 9999
GET / HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
问题已解决,现在标头的顺序正确,并且请求似乎与真正的 firefox 请求完全无法区分 :)(我实际上不推荐这最后一步,它是保持 CURLOPT_ENCODING 与自定义 Accept-Encoding 标头同步的维护负担,而且我从未遇到过标头顺序很重要的情况)