когда я отправляю запрос jsonp GET с помощью jQuery, он обычно отправляет что-то вроде:
http://website.com/test?callback=jQuery20309569547907449305_1386221743664&id=9&limit=10&_=1386221743665
в Zend Framework я буду обрабатывать это как:
$request = $this->getRequest();
$callback = $request->getParam('callback');
$id = $request->getParam('id');
$limit = $request->getParam('limit');
// set $response var to something
$this->getResponse()->setBody($callback . '(' . json_encode($response) . ');');
в Slim Framework у меня есть:
$callback = isset($_GET['callback']) ? $_GET['callback'] : '';
$app->get(
'/test',
function () {
$resp = array('This is a TEST route');
}
);
$app->response->setBody($callback . '(' . json_encode($resp) . ');');
но маршрут возвращает 404
любые идеи, как я могу работать?
Здесь есть несколько вещей. Во-первых, вы не должны получать 404, вы должны получить сообщение об ошибке, что $ resp не определен.
Я думаю, что вам, вероятно, не хватает.htaccess (или web.config, если вы работаете в IIS), который направляет все запросы в файл вашего фронтального контроллера (где вы определяете свой объект Slim и маршруты). Чтобы убедиться, что это проблема, попробуйте http://website.com/index.php/test?callback=whatever, где index.php - это имя файла вашего фронтального контроллера.
Это.htaccess, который я использую:
RewriteEngine On
#Slim PHP routing
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^/index.php
RewriteRule ^ index.php [QSA,NC,L]
Что касается попытки достичь того, чего вы хотите достичь, вам нужно что-то вроде этого:
$app = new Slim\Slim();
$app->get('/test', function () use($app) {
//Request processing begins here...
//Get callback from query string
$callback = $app->request()->get('callback');
//Check for null here...
//Set content type to javascript
header('Content-type: text/javascript');
//Generate our JSONP output
echo "$callback(" . json_encode(array('This is a test.')) . ");";
//Request processing ends here...
});
$app->run();
Я не на 100% знаком с Zend, но я думаю, что он использует более традиционную реализацию MVC, где у вас есть класс Controller, который вы расширяете и реализуете действия как методы. Slim намного более простой, чем это, вместо этого вы определяете маршруты на своих объектах приложения и сопоставляете их с закрытием, которые выполняются при ударе по их маршруту.
В моем примере выше я определяю закрытие маршрута '/test'. Закрытие в PHP не имеет доступа по умолчанию к другим переменным в их объеме. Чтобы получить доступ к переменной за пределами области закрытия, мы должны явно указать переменные, которые мы хотим, используя ключевое слово "use". В примере я "использую" объект $ app, так что мы можем использовать объект приложения внутри нашего закрытия. Это является основой для большинства функций, предоставляемых Slim. Объект $ app - это объект IOC, ядро, где все живет и должно использоваться для раскрытия объектов службы и т.д. В этом случае мы используем метод request(), который возвращает нам оболочку вокруг суперглобалов, связанных с запросами ($ _GET, $ _POST и т.д.).
Когда у нас есть наш параметр обратного вызова, мы можем проверить, а затем сгенерировать и отправить наш JSONP. Slim не абстрагирует (насколько я знаю) отправку данных обратно по отклику, вы должны просто использовать эхо, как в ванильном PHP. Вы также должны задать тип заголовка javascript, так как это то, что мы отправляем. Надеюсь это поможет.
Для Slim 3.x Просто добавьте промежуточное ПО в цепочку ответов
$app->add(function ($request, $response, $next) { // jsonp
$callback = $_GET['callback'] ?? false;
if($callback) $response->getBody()->write($callback."(");
$response = $next($request, $response);
if($callback) $response->getBody()->write(")");
return $response;
});
Я наткнулся на этот ответ, пытаясь поддержать ответы JSONP в Slim v3.
Ответ от @cardeol не совсем поддержал мои потребности, так как некоторые из моих предыдущих вызовов промежуточного программного обеспечения использовали "$response-> withJson ($ data, $ code);
Этот вызов уничтожает и воссоздает объект тела. Промывка любого "ПЕРЕД" записывается.
class JSONPResponseMiddleware {
/**
* Wrap response with callback query parameter
*
* @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* @param \Psr\Http\Message\ResponseInterface $response PSR7 response
* @param callable $next Next middleware
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, $next){
if(!$callback = $request->getQueryParam("callback", false)){
return $next($request, $response);
}
$response = $next($request, $response);
$data = $response->getBody();
// upstream controllers use "withJSON" which purges the existing body object.
$body = new Body(fopen('php://temp', 'r+'));
$body->write("{$callback}(");
$body->write($data);
$body->write(")");
$response = $response->withBody($body)->withHeader('Content-type', 'application/javascript');
return $response;
}
}
Затем устанавливается с помощью: $app->add(new JSONPResponseMiddleware());
Вы раньше работали с zend? Я не совсем уверен, знаете ли вы, как работает zend. У вас нет функций get()
с обратными вызовами, но у вас есть контроллер (в вашем случае: test
), и у этого контроллера есть несколько действий.
пример вашего текстового контроллера с примером действия может выглядеть примерно так:
class TestController extends Zend_Controller_Action
{
public function init()
{
//you might want to use here a contextSwitch
}
public function fooAction()
{
//get params
$limit = $this->_getParam('limit', 0);
[...]
//do stuff here
[...]
$this->_helper->json($response);
}
}
Теперь ваши призывы к этому действию могут выглядеть так:
http://website.com/test/foo/limit/10
Обратите внимание, что нет необходимости в уродливом ?param=value
в zend. просто добавьте его в URI с param/value
Примечание (важно): Есть $this->_helper->json($response)
способа в zend для вывода json
, поэтому $this->_helper->json($response)
может быть не лучшим решением для вас. Использование contextSwitch внутри вашей функции init()
может быть лучше.
$app->response->setBody()
, я не хотел бы использоватьheader('Content-type: text/javascript');
потому что это может быть не то, что мне нужно