关于400 Bad Request的问题

你们好,小弟这里有个问题想请教。

我的网页现在需要链接mobile API,他们只是需要我的网页回复他们的XML data,

例如

  1. User Sign Up (function = signUP)

Submit($_POST): first name, last name, password, email address, gender, date of birth,function=""

Return(XML Format): Sign Up status (successful with user ID, failed, or email taken, etc)

  1. User Sign In (function = signIn)

Submit($_POST): email, password

Return(XML Format): Sign In status (successful with user ID or failed)

小弟本身没有XML的经验,所以接开发了XML(controllers/model/CRUD)

然后就在xml/index等候他们的$_POST 请求

我本身也测试了自己的$_POST

然后server回复如下;

我问了mobile的开发员这样的格式是否正确,他们也说可以。

问题当他们正真测试的时候,他们回复说:

400 bad request,

是否需要config urlmanager?

顶起先 :lol:

没这方面经验 所以期待 其他人解答了 ;

不过 从以往资料来看 手机连接到你网站应该到一个唯一route上

比如 api/xml api/json api/html 控制器的actionXxx 处理不同格式的数据。 这些都应该是唯一访问点 你不要搞出多种来 比如 user/login user/signup 等…

然后 这些action中都只是 监听而已 需要架设server(RPC server) 比如:




class ApiController extends CController

{


    public function actionRpc(){

      //  die(__METHOD__);

        Yii::log("enter ". __METHOD__, CLogger::LEVEL_INFO);

        Yii::import('application.vendors.json_rpc.jsonRPCServer');


        $serviceProxy = YsService::instance();


        jsonRPCServer::handle($serviceProxy)

            or print 'no request';

        Yii::log("end ". __METHOD__, CLogger::LEVEL_INFO);

        die();

    }




} 



然后然后 有中心service来处理不同的请求 rpc 远程过程调用会跟本地类似的 这里需要一个映射表

格式如: apiName => apiServiceImplementCallable

键值应该是 api的外部调用的名字 比如 user_login user_signUP … 全部是字符串 但你要做某些前缀用来区分模块 防止 以后出现名字冲突 。

值 部分 绑定的是 php callable (你自己查 常见的 有 方法名, 类名::静态方法名 array($obj,‘methodName’)) 所以你要考虑如何将外部apiName 映射到本机上的函数 静态方法名 或者 对象的方法上 。 你搜索下 php RPC 应该可以找到相关库 很多的。

你最好 在提供一个service层 底层调用相应的Ar的功能; 比如 UserService 调用User 类来完成相关的业务方法 比如 siginIn 等对外暴露的服务方法。 但注意返回值 不能是ar了 转换成数组先 然后有好多库 可以辅助将 数组转换为xml或者json 格式 。难点在 复杂类型处理上 比如引用 关系型($photo->user )可能需要递归转换 … 还有考虑 分页问题 反正要考虑的太多了 。

我没这方面经验 所以只是我的想法而已 仅供参考。 下面给出我的 YsService 类的实现:




class YsService extends CApplicationComponent

{


    /**

     * @static

     * @return YsService

     */

    public static function instance()

    {

        if (!isset(Yii::app()->service)) {


            Yii::app()->setComponents(array(

                'service' => array(

                    'class' => __CLASS__,

                   // 'mode' => self::MODE_LOCAL,

                ),

            ), false);

        }

        return Yii::app()->service;

    }


    const MODE_JSON_RPC = 'json_rpc';

    const MODE_XML_RPC = 'xml_rpc';

    /**

     * @see http://www.phprpc.org/zh_CN/

     */

    const MODE_PHP_RPC = 'php_rpc';

    const MODE_LOCAL = 'local';

    /**

     * @see http://code.google.com/p/fastcgirpc/

     */

    const MODE_FAST_RPC = 'fast_rpc';


    /**

     * @static

     * @param string $moduleId

     * @param string $serviceName

     * @param array $params

     * @return mixed|void

     */

    static public function call($moduleId = '', $serviceName = '', $params = array())

    {

         return self::instance()->callModuleService($moduleId,$serviceName,$params);

    }


    public $mode = self::MODE_LOCAL;


    protected $modulePath = array();




    public function callModuleService($moduleId = '', $serviceName = '', $params = array())

    {


        if ($this->mode = self::MODE_LOCAL) {

            return $this->callLocalModuleService($moduleId, $serviceName, $params);

        } elseif ($this->mode = self::MODE_JSON_RPC) {

            return $this->callJsonRpcModuleService($moduleId,$serviceName,$params);

        } else {

            throw new CException("the {$this->model} is not supported yet");

        }

    }


    /**

     * @param string $moduleId

     * @param string $serviceName

     * @param array $params

     * @return mixed

     */

    protected function callLocalModuleService($moduleId = '', $serviceName = '', $params = array())

    {

        $modulePath = $this->getModulePath($moduleId);

        if (($pos = strpos($serviceName, '.')) !== false) {

            $serviceClassName = ucfirst(substr($serviceName, 0, $pos)) . "Service";

            $serviceMethodName = substr($serviceName, $pos + 1);

        } else {

            $serviceClassName = ucfirst($moduleId) . "Service";

            $serviceMethodName = $serviceName;

        }

        $servicePath = $modulePath . DIRECTORY_SEPARATOR . 'services' . DIRECTORY_SEPARATOR . "{$serviceClassName}.php";


        require_once($servicePath);


        $serviceObj = new $serviceClassName();

        // setMode

        if($serviceObj instanceof IModuleService){

            $serviceObj->setProcessMode($this->mode);

        }

        return call_user_func_array(array($serviceObj, $serviceMethodName), $params);

    }


    /**

     * @param $moduleId 目前只支持平面化module 不支持更深层次的module嵌套了

     * @return string

     * 如果通过moduleId 去找模块的路径 影响单元测试的 很麻烦

     * 所以模块下的service 不要通过 module本身来提供 dolphin是module自身提供serviceXXX方法的

     */

    protected function getModulePath($moduleId = '')

    {

        // return  dirname(Yii::app()->getModule($moduleId)->getModulePath());

        $modulePath = Yii::app()->getModulePath();

        return $modulePath . DIRECTORY_SEPARATOR . $moduleId;

    }


    protected function callJsonRpcModuleService($moduleId = '', $serviceName = '', $params = array())

    {

        Yii::import('application.vendors.json_rpc.jsonRPCClient');

        //$serviceRemoteProxy = new jsonRPCClient($this->createAbsoluteUrl('/api/rpc'),true);

        $serviceRemoteProxy = new jsonRPCClient($this->createAbsoluteUrl('/api/rpc'));


        try {

            echo $serviceRemoteProxy->callModuleService($moduleId,$serviceName,$params);


        } catch (Exception $e) {

            echo nl2br($e->getMessage()).'<br />'."\n";

        }

    }


}




还有 现在跟第三方交互 都趋于 json或者二进制了 建议最好不要用soap 虽然这种方法很通用 但xml格式数据浪费数据很严重的 我倾向使用 json 。 现在php也有 json rpc 实现 其他语言也有 当然手机可能也有 你自己搜索吧

谢谢你的建议哈

因为刚学习YII,没想到这么快就要学别的语言。