如何在Yii框架中使用HTTP PING?

时间:2015-03-20 05:19:39

标签: php yii yii2

我正在尝试使用HTTP PING请求,我的操作作为直接GET请求进行测试,但是当我对其进行测试时,Yii会返回400 Bad Request

<a href="<?= Url::toRoute(['shopping/ping', 'id' => (string)$item->productId, 
  'category' => (string)$item->primaryCategory->categoryId]) ?>">test</a>
<a href="<?= $item->viewItemURL ?>" ping="<?= Url::toRoute(['shopping/ping', 'id' => (string)$item->productId, 
  'category' => (string)$item->primaryCategory->categoryId]) ?>">  

这是浏览器发送的请求:

POST /aa/web/index.php?r=shopping%2Fping&id=102712943&category=122930 HTTP/1.1
Host: localhost:81
Connection: keep-alive
Content-Length: 4
Origin: http://localhost:81
Ping-From: http://localhost:81/aa/web/index.php?r=shopping%2Fsearch
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Content-Type: text/ping
Cache-Control: max-age=0
Ping-To: http://www.ebay.com/itm/Oster-TSSTTVVG01-4-Slice-Toaster-Oven-Black-Free-Shipping-New-/111355397466?pt=LH_DefaultDomain_0
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: ...chocolate chip...

PING

这是回复:

HTTP/1.1 400 Bad Request
Date: Fri, 20 Mar 2015 04:46:37 GMT
Server: Apache/2.2.29 (Unix) mod_ssl/2.2.29 OpenSSL/1.0.1k DAV/2 PHP/5.6.6
X-Powered-By: PHP/5.6.6
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Set-Cookie: ...
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

我的猜测是因为内容类型,或者因为它是带有URL参数的POST请求,而且正文没有路径。

此处为curl请求。

$ curl "http://localhost:81/aa/web/index.php?r=shopping"%"2Fping&id=102712943&category=122930" -H "Origin: http://localhost:81" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: en-US,en;q=0.8" -H "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36" -H "Content-Type: text/ping" -H "Accept: */*" -H "Ping-From: http://localhost:81/aa/web/index.php?r=shopping"%"2Fsearch" -H "Cookie: _ga=GA1.1.1670952969.1415577943; _sp_id.1fff=1d72e39980ea4f9f.1418093158.62.1423448353.1420663798; _csrf=62bd0371770906a42eb6da654fb4345ba51adb9272a26d1dc8ce6d28908f6610a"%"3A2"%"3A"%"7Bi"%"3A0"%"3Bs"%"3A5"%"3A"%"22_csrf"%"22"%"3Bi"%"3A1"%"3Bs"%"3A32"%"3A"%"22Dq2_r1KD_6GR-rHBEm3b4g6foEKxFL5q"%"22"%"3B"%"7D; PHPSESSID=j4unbucemcp4pj1h87qimld596; _identity=df1823bd01881d804ff9655d79364c898d2ad574cc769f3a53fb104dde8e3f88a"%"3A2"%"3A"%"7Bi"%"3A0"%"3Bs"%"3A9"%"3A"%"22_identity"%"22"%"3Bi"%"3A1"%"3Bs"%"3A28"%"3A"%"22"%"5B"%"22100"%"22"%"2C"%"22test100key"%"22"%"2C2592000"%"5D"%"22"%"3B"%"7D" -H "Connection: keep-alive" -H "Cache-Control: max-age=0" -H "Ping-To: http://www.ebay.com/itm/Oster-TSSTTVVG01-4-Slice-Toaster-Oven-Black-Free-Shipping-New-/111355397466?pt=LH_DefaultDomain_0" --data-binary "PING"                 
...
<h1>Bad Request (#400)</h1>

我回到我的应用程序并单击调试器栏,并加载了失败的请求。这是它给出的错误和堆栈跟踪。

exception 'yii\web\BadRequestHttpException' with message 'Unable to verify your data submission.' in /cygdrive/c/Users/Chloe/workspace/AffiliateArbitrage/vendor/yiisoft/yii2/web/Controller.php:110
Stack trace:
#0 /cygdrive/c/Users/Chloe/workspace/AffiliateArbitrage/vendor/yiisoft/yii2/base/Controller.php(149): yii\web\Controller->beforeAction(Object(yii\base\InlineAction))
#1 /cygdrive/c/Users/Chloe/workspace/AffiliateArbitrage/vendor/yiisoft/yii2/base/Module.php(455): yii\base\Controller->runAction('ping', Array)
#2 /cygdrive/c/Users/Chloe/workspace/AffiliateArbitrage/vendor/yiisoft/yii2/web/Application.php(83): yii\base\Module->runAction('shopping/ping', Array)
#3 /cygdrive/c/Users/Chloe/workspace/AffiliateArbitrage/vendor/yiisoft/yii2/base/Application.php(375): yii\web\Application->handleRequest(Object(yii\web\Request))
#4 /cygdrive/c/Users/Chloe/workspace/AffiliateArbitrage/web/index.php(12): yii\base\Application->run()
#5 {main}

如何让此请求生效?

2 个答案:

答案 0 :(得分:1)

以下是我对这个问题的理解。首先,您获得的错误与csrf验证直接相关。验证失败,因此永远不会处理请求。当您单击该链接时,您正在发出GET请求,因此不会调用csrf验证。

然而,ping属性通过POST方法向服务器提交请求。因为它是一个POST方法,所以Yii期望在请求的主体中找到一个有效的csrf令牌,因为没有提交任何表单。

回退是检查标头以查看标头HTTP_X_CSRF_TOKEN中是否有有效的csrf标记,因此可能是您可以编写一些javascript来拦截ping请求并添加所需的标头,从中获取令牌现有的cookie。我的javascript写得不够好,所以我无法测试它!

另一种选择是编写一个新的控制器类,覆盖默认控制器的beforeAction()方法以删除csrf验证部分,并让您的特定ShoppingController扩展该新控制器。

希望这有帮助!

答案 1 :(得分:0)

是的,这是因为CSRF,这是一个解决方案:

  public function beforeAction($action) {
    // Yii::trace($action); // this will prevent debug bar from showing!
    if ($action->id == 'ping') $this->enableCsrfValidation = false;
    return parent::beforeAction($action);
  }

我标记了另一个答案,即使没有例子,也可以赞扬这个建议。