简易http接口实现[通俗易懂]

简易http接口实现[通俗易懂]http接口是什么,我一直没找到比较明确的定义(如果有哪位可以提点一下,我将非常感谢),今天就自己来总结一下吧。个人认为,http接口就是一种基于http服务的api,是系统之间交互的一种约定,所谓的webservice其实也就是一种http接口,只不过它是比较规范的、通用的。       http接口有什么用,个人体会是,http接口最主要的作用是能够较好地解决不同系统(可能是功能不同、

大家好,又见面了,我是你们的朋友全栈君。

        http接口是什么,我一直没找到比较明确的定义(如果有哪位可以提点一下,我将非常感谢),今天就自己来总结一下吧。个人认为,http接口就是一种基于http服务的api,是系统之间交互的一种约定,所谓的web service其实也就是一种http接口,只不过它是比较规范的、通用的。

        http接口有什么用,个人体会是,http接口最主要的作用是能够较好地解决不同系统(可能是功能不同、开发语言不同、服务商不同,等等,但都是基于http服务的)之间的交互的需求,比如像微信公众号的各种接口,不管是使用Java开发还是PHP进行开发,不管是A公司在开发还是B公司在开发,也不管是要做商城系统还是做企业宣传网站,都一样可以很好地调用。

        接下来就展现一套自己写的简易的http接口,作为自己这段时间学习与实践的一个小总结。这套接口的基本框架,在本人的具体开发实践中是有用到的,目前来看,运行效率和可扩展性还算能满足需要。

        下图就是整个框架项目的目录结构

简易http接口实现[通俗易懂]

        整个接口服务端的处理流程如下:

        1、接收并解析请求;

        包括检查数据格式、验证签名等。

        2、根据请求实例化对应的处理器;

        简单工厂模式,映射规则为:接口名称为test,则实例化apis\TestApi类。

        3、处理器具体处理请求;

        调用处理器的handle()方法,比如userinfo接口,handle()可能就是去数据库中查找响应的user信息。

        4、处理器输出响应

        调用response()方法。

 

        前面也说了,接口是一种约定,因此发送数据和输出响应都是要遵循这个约定的,一般情况下,约定分为总体约定和具体接口约定两个部分,总体约定如下:

        1、以http的post方式提交数据,数据在$_POST中的键名为data;

        2、数据提交时需要先后经过json和base64编码,中文需保持原样,输出的响应同样如此;

        3、提交数据的格式:

   $data = [

      ‘api’ => ‘userinfo’, // 具体接口名称,必须

      ‘noncestr’ => ‘123’,// 随机字符串,必须

      ‘serial’ => ‘123’, // 调用流水号,必须

      ‘signature’ => ‘xxx’, // 签名,必须

      ‘body’ => [

         … // 请求详细数据,由具体接口约定,可选

      ]

   ];

   4、响应数据的格式:

   $data = [

      ‘code’ => 0, // 状态码,0为调用成功,非0为失败,必须

      ‘serial’ => ‘123’, // 调用流水号,必须

      ‘signature’ => ‘xxx’, // 签名,非必须

      ‘body’ => [

         … // 响应详细数据,由具体接口约定,可选

      ]

   ];

 

以下是各文件的代码:

aHttpApiHandler.php

<?php

namespace apis;
use libraries\HttpApiUtil;

/**
 * api处理器抽象类
 */
abstract class aHttpApiHandler {
	/**
	 * 请求数据
	 * @var array
	 */
	protected $data = [];
	
	/**
	 * 处理结果
	 * @var array
	 */
	protected $result = [];
	
	/**
	 * 处理请求
	 */
	abstract function handle();
	
	/**
	 * 构造方法
	 * @access public
	 * @param array $data
	 * @return void
	 */
	public function __construct($data) {
		$this->data = $data;
	}
	
	/**
	 * 输出响应
	 * @access public
	 * @return mixed
	 */
	public function response() {
		$result = HttpApiUtil::makeReturn(0, '', $this->data['serial'], $this->result);
		echo base64_encode(json_encode($result, JSON_UNESCAPED_UNICODE));
	}	
}

TestApi.php

<?php

namespace apis;

/**
 * test接口
 */
class TestApi extends aHttpApiHandler {
	/**
	 * 处理请求
	 * @access public
	 * @return mixed
	 */
	public function handle() {
		echo '调用' . __CLASS__ . '处理请求', PHP_EOL;
	}
	
	/**
	 * 输出响应
	 * @access public
	 * @return mixed
	 */
	public function response() {
		echo '调用' . __CLASS__ . '处理请求完毕,输出响应', PHP_EOL;
	}
}

UserinfoApi.php

<?php

namespace apis;

/**
 * userinfo接口
 */
class UserinfoApi extends aHttpApiHandler {
	/**
	 * 处理请求
	 * @access public
	 * @return mixed
	 */
	public function handle() {
		// 模拟从数据库取得用户信息
		$id = $this->data['body']['id'];
		$this->result = [
			'id' => $id,
			'name' => 'webmaster',
			'nickname' => 'web管理员'
		]; 
	}
}

common.php

<?php

/**
 * 类自动加载函数
 */
function api_autoload($class) {
	@include $class . '.php';
}

// 设置自动加载路径
$includePath = ['apis', 'libraries'];
$includePath = implode(';', array_map(function($v){
	return ROOT_PATH . '/' . $v;
}, $includePath));
set_include_path($includePath);

// 注册自动加载函数
spl_autoload_register('api_autoload');

CurlUtil.php

<?php

namespace libraries;

/**
 * curl工具类
 */
class CurlUtil {
	/**
	 * 以post方式获取结果
	 * @access public
	 * @param string $url url地址
	 * @param string $data 数据
	 * @throws \Exception
	 * @return string
	 */
	public static function doPost($url, $data = null) {
		// 初始化
		if (!$ch = curl_init()) throw new \Exception('curl初始化失败');
		
		// 设置选项
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		
		if ($data) {
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
		}
		
		$result = curl_exec($ch);
		if (curl_errno($ch)) throw new \Exception(curl_error($ch));
		
		curl_close($ch);
		
		return $result;
	}
}

HttpApiConfig.php

<?php

namespace libraries;

/**
 * api配置类
 */
class HttpAPiConfig {
	/**
	 * 签名key
	 * @var string
	 */
	const KEY = 'key for signature';
}

HttpApiError.php

<?php

namespace libraries;

/**
 * api错误定义
 */
class HttpApiError {
	/**
	 * 数据格式错误
	 * @var integer
	 */
	const INVALID_DATA = 10001;
	
	/**
	 * 数据解析错误
	 * @var integer
	 */
	const DATA_PARSE_ERROR = 10002;
	
	/**
	 * 签名错误
	 * @var integer
	 */
	const INVALID_SIGNATURE = 10003;
	
	/**
	 * 接口不存在
	 * @var integer
	 */
	const INVALID_API = 10004;
	
	/**
	 * 无法创建处理器
	 * @var integer
	 */
	const CANT_CREATE_HANDLER = 10005;
	
	/**
	 * 未知错误
	 * @var integer
	 */
	const UNKNOWN_ERROR = 90001;
	
	/**
	 * 错误码与错误信息映射
	 * @var array
	 */
	private static $errors = [
		10001 => '数据格式错误',
		10002 => '数据解析错误',
		10003 => '签名错误',
		10004 => '接口不存在',
		10005 => '无法创建处理器',
		90001 => '未知错误',
	];
	
	/**
	 * 获取错误信息
	 * @access public
	 * @param integer $code 错误码
	 * @return mixed
	 */
	public static function getError($code) {
		return isset(self::$errors[$code]) ? self::$errors[$code] : false;
	}
}

HttpApiHandlerFactory.php

<?phpnamespace libraries;/** * api处理器工厂 */class HttpApiHandlerFactory {	/**	 * 生成api处理器实例	 * @access public	 * @param string $data	 * @throws \Exception	 * @return \libraries\aHttpApiHandler	 */	public static function create($data) {		$info = HttpApiParser::parse($data);		if ($info['code']) {			throw new \Exception($info['msg'], $info['code']);		}				$request = $info['body'];		$class = '\\apis\\' . ucfirst(strtolower($request['api'])) . 'Api';		try {			$rfc = new \ReflectionClass($class);			return $rfc->newInstance($request);		} catch (\Exception $e) {			throw new \Exception(HttpApiError::getError(HttpApiError::CANT_CREATE_HANDLER), HttpApiError::CANT_CREATE_HANDLER);		}			}}

HttpApiParser.php

<?phpnamespace libraries;/** * api请求解析器 */class HttpApiParser {	/**	 * 解析请求	 * @access public	 * @param string $data	 * @return array	 */	public static function parse($data) {		if (!is_array($data) || !array_key_exists('data', $data)) {				return HttpApiUtil::makeReturn(HttpApiError::INVALID_DATA, HttpApiError::getError(HttpApiError::INVALID_DATA));		}				$request = json_decode(base64_decode($data['data']), true);		if (json_last_error()) {			return HttpApiUtil::makeReturn(HttpApiError::UNKNOWN_ERROR, HttpApiError::getError(HttpApiError::UNKNOWN_ERROR));		}				// 检查数据格式		if (empty($request['api'])			|| empty($request['noncestr'])			|| empty($request['serial'])			|| empty($request['signature'])) {				return HttpApiUtil::makeReturn(HttpApiError::INVALID_DATA, HttpApiError::getError(HttpApiError::INVALID_DATA));		}				// 检查签名		if ($request['signature'] != HttpApiUtil::makeSign($request)) {			return HttpApiUtil::makeReturn(HttpApiError::INVALID_SIGNATURE, HttpApiError::getError(HttpApiError::INVALID_SIGNATURE), $request['serial']);		}				return HttpApiUtil::makeReturn(0, '', $request['serial'], $request);	}}

index.php

<?php// 接收请求use libraries\HttpApiHandlerFactory;use libraries\HttpApiUtil;define('ROOT_PATH', __DIR__);include ROOT_PATH . '/common/common.php';// **************************************// 创建处理器try {	$api = HttpApiHandlerFactory::create($_POST);} catch (\Exception $e) {	print_r(HttpApiUtil::makeReturn($e->getCode(), $e->getMessage()));	exit();}// 执行操作$api->handle();$api->response();

test.php

<?php

// 发起调用

use libraries\HttpApiUtil;
use libraries\CurlUtil;

define('ROOT_PATH', __DIR__);
include ROOT_PATH . '/common/common.php';

// **************************************

$url = 'http://api.local.com/index.php';
$data = [
	'api' => 'test',
	'noncestr' => HttpApiUtil::makeNoncestr(),
	'serial' => HttpApiUtil::makeSerial(),
	'body' => [
	]
];
$data['signature'] = HttpApiUtil::makeSign($data);

$json = 'data=' . base64_encode(json_encode($data));
try {
	$response = CurlUtil::doPost($url, $json);
	echo $response;//  原始输出
	print_r(json_decode(base64_decode($response), true));
} catch (Exception $e) {
	echo $e->getMessage();
}

OK,简易的http接口就是这样了,如果要新增一个具体接口,比如查看用户列表,可以考虑新增一个apis\UserlistApi类,继承aHttpApiHandler类并实现相应的方法即可了。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/142475.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Python中字符串String去除出换行符(\n,\r)和空格的问题「建议收藏」

    Python中字符串String去除出换行符(\n,\r)和空格的问题「建议收藏」Python中字符串String去除出换行符和空格的问题(\n,\r)在Python的编写过程中,获取到的字符串进场存在不明原因的换行和空格,如何整合成一个单句,成为问题。方法:一、去除空格“·”代表的为空格  strip()"···xyz···".strip()#returns"xyz""···xyz···".lstrip()…

  • armv7在哪儿看(armv7s)

    iOS中的armv7,armv7s,arm64,i386,x86_64都是什么在做静态库的时候以及引用静态库的时候经常会遇到一些关于真机模拟器不通用的情况,会报错找不到相应库导致编译失败,这里简单记录一下各种设备支持的架构。iOS测试分为模拟器测试和真机测试,处理器分为32位处理器,和64位处理器,模拟器32位处理器测试需要i386架构,(iphone5,iphone5s以下的模拟器…

  • 解决Python扩展: Unable to find vcvarsall.bat[通俗易懂]

    解决Python扩展: Unable to find vcvarsall.bat[通俗易懂]安装mingw,以我的安装为例:我的mingw安装在C:\MinGW,python安装在C:\Python26然后将以下目录加入系统环境变量C:\MinGW\bin;C:\MinGW\msys\1.0;C:\MinGW\mingw32;C:\MinGW\mingw32\bin;C:\MinGW\msys\1.0\bin然后在目录C:\Python26\Lib\di…

  • python标识符号_python标识符的组成元素

    python标识符号_python标识符的组成元素在Python里,标识符由字母、数字、下划线组成,但不能以数字开头。#Python中标识符区分大小写。#以下划线开头的标识符有特殊意义,以单下划线开头_foo的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用fromxxximport*而导入。##以双下划线开头的__foo代表类的私有成员,以双下划线开头和结尾的__foo__代表Python里特殊方法专用的标识,如__init__()代表类的构造函数。##Python可以同一行显示多.

  • 函数模板与同名的非模板函数不可以重载(重载的定义)

    关于函数的重载机制,是一个比较复杂的问题,其中涉及到了优先级定义和最佳匹配等问题,如果要阐述清楚,恐怕不是一两篇文章就能说的明白。但是如果掌握了一些常用的“规律”,对于了解程序对重载函数是如何进行选择也有很大的好处,本文尝试将自己理解的知识,结合下面简单的例子简略的说说函数重载机制,文章的摘录部分列出了一些关于程序如何选择重载函数的规则。:)例子如下:#include

  • 更新pip版本(anaconda更新pip)

    @更新pip版本#window:正常windows下更新pip版本的指令无法更新时,可以尝试如下指令python-mpipinstall–upgradepip#Ubuntu更新pip版本指令:sudo-Hpython-mpipinstall–upgradepip…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号