创建以API为中心的Web应用(转)
英文原文:Creating an API-Centric Web Application
引言
API——API是Application Programming Interface(应用编程接口)的简称。根据维基百科:
API是以源代码为基础的约定,它用于软件组件之间相互通信的接口。API可能包含函数、数据结构、对象类、以及变量等的约定。
API可视化
简单地讲,API指的是一组应用中的函数,它们能够被其它应用(或者这些函数所属应用自己,下文中我们将会看到)用来与应用进行交互。API是一种很棒的向外部应用安全和妥善地表明其功能的方式,因为这些外部应用所能利用的所有功能仅限于API中所表现出的功能。
什么是“以API为中心的”网络应用?
以API为中心的网络应用就是基本上通过API调用执行大多数甚或所有功能的一类网络应用。
以API为中心的网络应用就是基本上通过API调用执行大多数甚或所有功能的一类网络应用。举个例子,如果你正要登录一个用户,你应当将其认证信息发送给API,然后API会向你返回一个结果,说明该用户是否提供了正确的用户名-密码组合。
以API为中心的网络应用的另外一个特征就是API一直是无状态的,这意味着这种应用无法辨别由会话发起的API调用。由于API调用通常由后端代码构 成,实现对会话的掌控将比较困难,因为这其中通常没有cookies介入。这种局限事实上是好事——它“迫使”开发者建造不基于当前用户状态工作的 API,但是相应地在功能上,它使测试易于进行,因为用户的当前状态无需被重建。
为什么要经历这些麻烦?
作为Web开发者,我们已经亲眼目睹了技术的进步。有一个常识是,当代的人们不会只通过浏览器来使用应用,还会通过其它诸如移动电话和平板电脑之类的设备使用。举个例子,这篇发表在Mashable上的名为“用户在移动应用上花的时间比在网络上的多”的写道:
一项新近的报告表明,用户花在移动应用上的时间首次超过了花在网络上的时间。
Flurry对比了其移动数据与来自comScore和Alexa的统计数据,发现在六月,用户每天花费81分钟使用移动应用,而只花74分钟用于网上冲浪。
这里还有一篇来自ReadWriteWeb的更新的文章“在移动设备上浏览网络的人多于使用IE6和IE7的人数总和”
来自Sitepoint的 浏览器趋势的 最新数据表明,在智能手机上浏览Web的人比使用IE6和IE7浏览的人更多。这两件难有起色的老古董多年来一直是Web开发者的噩梦,它们需要各网站尽 可能妥当地降格到至少常用浏览器所能支持的水平。但是现在时代不同了;2011年十一月中,6.95%的Web活动在移动浏览器上发生,而发生在IE6或 IE7上的则只有6.49%。
正如我们所见,越来越多的人正通过其它途径获得讯息,特别是移动设备。
这与我创建以API为中心的网络应用有何关系?
创建以API为中心的网络应用的主要优势之一便是它帮助你建立可以用于任何设备的功能,浏览 器、移动电话、甚至是桌面应用。你所需要做的就是创建的API 能够使所有这些设备利用它完成通信,然后,瞧!你将能够建造一个集中式应用,它能够接受来自用户所使用的任何设备的输入并执行相应的功能。
以API为中心的应用的框图
通过以这种方式创建应用,我们能够从容地利用不同的人使用不同的媒介这一优势。这必将使应用更加有用,因为它能用在用户需要的任何地方。
为了证明我们的观点,这里有一篇关于Twitter的重新设计的网站的文章,文章告诉我们他们现在如何利用他们的API来驱动Twitter.com的,实质上是使其以API为中心:
最重要的架构改动之一就是Twitter.com现在是我们自己API的客户。它从终端提取数据,此终端与移动网站,我们为iPhone、iPad、 Android,以及所有第三方应用所用端点相同。这一转变使我们能向API团队分配更多的资源,同时生成了40多个补丁。在初始页面负载和来自客户端的 每个调用上,所有的数据现在都是从一个高度优化的JSON段缓存中获取的。
在本篇教程中,我们将创建一个简单的TODO列表应用,该应用以API为中心;还要创建一个浏览器上的前端客户端,该客户端与我们的TODO列表应用进行 交互。文末,你就能了解一个以API为中心的应用的有机组成部分,同时,还能了解怎样使应用和客户端两者之间的安全通信变得容易。记住这些,我们开始吧!
步骤 1: 规划该应用的功能
本教程中我们将要构建的这个 TODO 应用将会有下面几个基本的CRUD功能:
- 创建 TODO 条目
- 读取 TODO 条目
- 更新 TODO 条目 (重命名,标记为完成,标记为未完成)
- 删除 TODO 条目
每一个 TODO 条目将拥有:
- 一个标题 Title
- 一个截止日期 Date Due
- 一个描述 Description
- 一个判断 TODO 条目是否完成的标志 Is Done
让我们模拟一下该应用,使我们考虑该应用以后会是什么样子时,能有有一个直观的参考:

简单的TODO 模拟示例
步骤 2: 创建API服务器
既然我们是在开发一个以API为中心的应用,我们将创建两个“项目”: API 服务器,和前端客户端。 我们首先从创建API服务器开始。
在你的web server文件夹,创建一个文件夹,命名为simpletodo_api,然后创建一个index.php文件。这个index.php文件将作为一个访问API的前端控制器,所以,所有访问API服务器的请求都会由该文件产生。打开它并往里输入下列代码:
<?php
// 定义数据目录的路径
define('DATA_PATH', realpath(dirname(__FILE__).'/data')); //引入我们的models
include_once 'models/TodoItem.php'; //在一个try-catch块中包含所有代码,来捕获所有可能的异常!
try {
//获得在POST/GET request中的所有参数
$params = $_REQUEST; //获取controller并把它正确的格式化使得第一个字母总是大写的
$controller = ucfirst(strtolower($params['controller'])); //获取action并把它正确的格式化,使它所有的字母都是小写的,并追加一个'Action'
$action = strtolower($params['action']).'Action'; //检查controller是否存在。如果不存在,抛出异常
if( file_exists("controllers/{$controller}.php") ) {
include_once "controllers/{$controller}.php";
} else {
throw new Exception('Controller is invalid.');
} //创建一个新的controller实例,并把从request中获取的参数传给它
$controller = new $controller($params); //检查controller中是否存在action。如果不存在,抛出异常。
if( method_exists($controller, $action) === false ) {
throw new Exception('Action is invalid.');
} //执行action
$result['data'] = $controller->$action();
$result['success'] = true; } catch( Exception $e ) {
//捕获任何一次样并且报告问题
$result = array();
$result['success'] = false;
$result['errormsg'] = $e->getMessage();
} //回显调用API的结果
echo json_encode($result);
exit();
实质上,这里我们创建的是一个简单的前端控制器,它实现了下列功能:
- 接受一次拥有任意个参数的API调用
- 为本次API调用抽取出Controller和Action
- 进行必要的检查确保Controller和Action都存在
- 执行API调用
- 捕获异常,如果有的话
- 返回一个结果给调用者
除了需要创建index.php外你还需要创建三个文件夹: controllers, models 和 data.

- controllers 文件夹存放的是所有我们API服务器将会用到的的控制器。我们用MVC架构来使API服务器结构更清楚合理。
- models 文件夹存放所有API服务器要用到的数据模型。
- data 文件夹将会用来保存API服务器的任何数据。
在controllers文件夹下创建一个叫Todo.php的文件。这将是任何TODO列表有关任务的控制器。按照TODO应用所需提供的功能,向Todo控制器里面添加必要的方法:
<?php
class Todo
{
private $_params; public function __construct($params)
{
$this->_params = $params;
} public function createAction()
{
//create a new todo item
} public function readAction()
{
//read all the todo items
} public function updateAction()
{
//update a todo item
} public function deleteAction()
{
//delete a todo item
}
}
现在为每个action中添加必要的功能实现。我将会提供createAction()方法的源码,其他方法将留作作业。如果你觉得毫无头绪,你也可以下载示例的源码,从那里拷贝。
public function createAction()
{
//create a new todo item
$todo = new TodoItem();
$todo->title = $this->_params['title'];
$todo->description = $this->_params['description'];
$todo->due_date = $this->_params['due_date'];
$todo->is_done = 'false'; //pass the user's username and password to authenticate the user
$todo->save($this->_params['username'], $this->_params['userpass']); //return the todo item in array format
return $todo->toArray();
}
在文件夹models下创建TodoItem.php,这样我们就可以创建“条目添加”的代码了。注意:我并没有和数据库进行连接,相反我将信息保存到文件中,虽然这可以用任何数据库来实现,但是 这样做相对来说要容易些。
<?php
class TodoItem
{
public $todo_id;
public $title;
public $description;
public $due_date;
public $is_done; public function save($username, $userpass)
{
//get the username/password hash
$userhash = sha1("{$username}_{$userpass}");
if( is_dir(DATA_PATH."/{$userhash}") === false ) {
mkdir(DATA_PATH."/{$userhash}");
} //if the $todo_id isn't set yet, it means we need to create a new todo item
if( is_null($this->todo_id) || !is_numeric($this->todo_id) ) {
//the todo id is the current time
$this->todo_id = time();
} //get the array version of this todo item
$todo_item_array = $this->toArray(); //save the serialized array version into a file
$success = file_put_contents(DATA_PATH."/{$userhash}/{$this->todo_id}.txt", serialize($todo_item_array)); //if saving was not successful, throw an exception
if( $success === false ) {
throw new Exception('Failed to save todo item');
} //return the array version
return $todo_item_array;
} public function toArray()
{
//return an array version of the todo item
return array(
'todo_id' => $this->todo_id,
'title' => $this->title,
'description' => $this->description,
'due_date' => $this->due_date,
'is_done' => $this->is_done
);
}
}
createAction方法使用到TodoItem模型里面两个方法:
- save() – 该方法将TodoItem保存到一个文件中,如有必要,需要设置todo_id。
- toArray() – 该方法返回一个以变量为索引的数组Todo条目。
由于API需要通过HTTP请求调用,在浏览器输入如下地址测试API:
如果没有错,你应该在data文件夹下看到一个新的文件夹,在该文件夹里面有一个文件,文件内容如下:

createAction()结果
恭喜!您已经成功创建了一个的API服务器和API调用!
步骤3:确保API服务器具有APP ID和APP SECRET
目前,API服务器被设置为接受全部API请求。我们将需要将之限制在我们自己的应用上,以确保只有我们自己 的前端客户端能够完成API请求。另外,你实际上也可以创建一个系统,其中的用户可以创建他们自己的应用,而那些应用也用用对你的API服务器的访问权, 这与Facebook和Twitter的应用的的工作原理类似。
我们从为使用API服务器的用户创建一组id-密码对开始。由于这只是一个Demo,我们可以使用任何随机的、32位字符串。对于APP ID,我们将其设定为APP001。
再次打开index.php文件,然后用下列代码更新之:
<?php
// Define path to data folder
define('DATA_PATH', realpath(dirname(__FILE__).'/data')); //Define our id-key pairs
$applications = array(
'APP001' => '28e336ac6c9423d946ba02d19c6a2632', //randomly generated app key
);
//include our models
include_once 'models/TodoItem.php'; //wrap the whole thing in a try-catch block to catch any wayward exceptions!
try {
//*UPDATED*
//get the encrypted request
$enc_request = $_REQUEST['enc_request']; //get the provided app id
$app_id = $_REQUEST['app_id']; //check first if the app id exists in the list of applications
if( !isset($applications[$app_id]) ) {
throw new Exception('Application does not exist!');
} //decrypt the request
$params = json_decode(trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $applications[$app_id], base64_decode($enc_request), MCRYPT_MODE_ECB))); //check if the request is valid by checking if it's an array and looking for the controller and action
if( $params == false || isset($params->controller) == false || isset($params->action) == false ) {
throw new Exception('Request is not valid');
} //cast it into an array
$params = (array) $params;
...
...
...
我们在这里已经完成的实际上是实现一个非常简单的认证我们的前端客户端的方法,它利用了与公共-私有密钥认证相似的系统。基本上,这里给出的就是认证过程的步骤分解:
公钥加密
- 完成一个API调用,其中提供了$app_id和$enc_request
- $enc_request的值是API调用的参数,利用APP KEY进行加密。APP KEY绝对不会被发送到服务器,它只是被用来散列请求。此外,该请求只能利用APP KEY被解密
- 一旦API调用到达API服务器,它会查验它自己的应用列表是否与APP ID所提供的一致
- 当调用被发现,API服务器尝试利用与APP ID发送的密钥相匹配的密钥进行解密
- 如果请求被解密成功,那么继续执行程序
既然API服务器已经确保具有APP ID和APP SECRET,那么我们就可以开始编写使用API服务器的前端客户端了。
步骤4:创建浏览器客户端
我们从为前端客户端设定新建文件夹开始。在你的Web服务器上的文件夹中创建一个名为simpletodo_client_browser的文件夹。完成后,创建一个index.php文件,并将下列代码写进去:
<!DOCTYPE html>
<html>
<head>
<title>SimpleTODO</title> <link rel="stylesheet" href="css/reset.css" type="text/css" />
<link rel="stylesheet" href="css/bootstrap.min.css" type="text/css" /> <script src="js/jquery.min.js"></script>
<script src="js/jquery-ui-1.8.16.custom.min.js"></script> <style>
body {
padding-top: 40px;
}
#main {
margin-top: 80px;
text-align: center;
}
</style>
</head>
<body>
<div class="topbar">
<div class="fill">
<div class="container">
<a class="brand" href="index.php">SimpleTODO</a>
</div>
</div>
</div>
<div id="main" class="container">
<form class="form-stacked" method="POST" action="login.php">
<div class="row">
<div class="span5 offset5">
<label for="login_username">Username:</label>
<input type="text" id="login_username" name="login_username" placeholder="username" /> <label for="login_password">Password:</label>
<input type="password" id="login_password" name="login_password" placeholder="password" /> </div>
</div>
<div class="actions">
<button type="submit" name="login_submit" class="btn primary large">Login or Register</button>
</div>
</form>
</div>
</body>
</html>
这段代码的运行结果看起来就像这样:
SimpleTODO的登录页
需要注意的是我在这里已经包含了两个JavaScript文件和两个CSS文件:
- reset.css是你的标准CSS重置脚本。我使用了meyerweb.com css reset.
- bootstrap.min.css是Twitter Bootstrap
- jquery.min.js是最新版的jQuery library
- jquery-ui-1.8.16.custom.min.js是最新版的jQuery UI library
接下来,我们创建login.php文件来存储客户端会话中的用户名和密码。
<?php
//get the form values
$username = $_POST['login_username'];
$userpass = $_POST['login_password'];
session_start();
$_SESSION['username'] = $username;
$_SESSION['userpass'] = $userpass;
header('Location: todo.php');
exit();
这里,我们简单地为用户开启一次会话,所依据的是用户所提供的用户名和密码组合。这充当了简单的组合密钥,它允许用户访问某个特定用户名和密码组合所存储 的TODO项。然后我们重定向至todo.php,那里是我们开始与API服务器交互的地方。然而在我们开始编写todo.php文件之前,先创建一个 ApiCaller类,它将封装我们所需的全部API调用方法,包括请求的加密。
创建apicaller.php,并把下面的代码写进去:
<?php
class ApiCaller
{
//some variables for the object
private $_app_id;
private $_app_key;
private $_api_url; //construct an ApiCaller object, taking an
//APP ID, APP KEY and API URL parameter
public function __construct($app_id, $app_key, $api_url)
{
$this->_app_id = $app_id;
$this->_app_key = $app_key;
$this->_api_url = $api_url;
} //send the request to the API server
//also encrypts the request, then checks
//if the results are valid
public function sendRequest($request_params)
{
//encrypt the request parameters
$enc_request = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->_app_key, json_encode($request_params), MCRYPT_MODE_ECB)); //create the params array, which will
//be the POST parameters
$params = array();
$params['enc_request'] = $enc_request;
$params['app_id'] = $this->_app_id; //initialize and setup the curl handler
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->_api_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, count($params));
curl_setopt($ch, CURLOPT_POSTFIELDS, $params); //execute the request
$result = curl_exec($ch); //json_decode the result
$result = @json_decode($result); //check if we're able to json_decode the result correctly
if( $result == false || isset($result['success']) == false ) {
throw new Exception('Request was not correct');
} //if there was an error in the request, throw an exception
if( $result['success'] == false ) {
throw new Exception($result['errormsg']);
} //if everything went great, return the data
return $result['data'];
}
}
我们将利用ApiCaller类向我们的API服务器发送请求。这样,所有必需的加密和cURL初始化代码将会写在一个地方,我们就不用重复代码了。
- __construct函数接受三个参数:
- $app_id——客户端的APP ID(浏览器端是APP001)
- $app_key——客户端的APP KEY(浏览器端是28e336ac6c9423d946ba02d19c6a2632)
- $api_url——API服务器的URL,此处为http://localhost/simpletodo_api/
- sendRequest()函数:
- 利用mcrypt库以API服务对其解密的同样方式来对请求参数进行加密
- 生成发往API服务器的$_POST参数
- 通过cURL执行API调用
- 查验API调用的结果是否正确
- 当一切都按计划进行的时候返回数据
现在,我们开始写todo.php。首先,我们创建一些代码来为密码为test1234的用户nikko(这是我们先前用来测试API服务器的那个用户名/密码组合)获取当前的todo项。
<?php
session_start();
include_once 'apicaller.php'; $apicaller = new ApiCaller('APP001', '28e336ac6c9423d946ba02d19c6a2632', 'http://localhost/simpletodo_api/'); $todo_items = $apicaller->sendRequest(array(
'controller' => 'todo',
'action' => 'read',
'username' => $_SESSION['username'],
'userpass' => $_SESSION['userpass']
)); echo '';
var_dump($todo_items);
打开index.php,以nikko/tes1234登录,然后你应该看到我们先前创建的TODO项的avar_dump()。
恭喜,你已经成功地做好了一个向API服务器的API调用!在这段代码中,我们已经:
- 开启会话,使我们拥有了对$_SESSION中的username以及userpass的访问权
- 实例化了一个新的ApiCaller类,为其提供了APP ID,APP KEY,以及API服务器的URL
- 通过sendRequest()方法发送了一个请求
现在,我们来重新格式化一下数据,让它们开起来更好看些。向todo.php中添加下列HTML。别忘了移去var_dump()!
<!DOCTYPE html>
<html>
<head>
<title>SimpleTODO</title> <link rel="stylesheet" href="css/reset.css" type="text/css" />
<link rel="stylesheet" href="css/bootstrap.min.css" type="text/css" />
<link rel="stylesheet" href="css/flick/jquery-ui-1.8.16.custom.css" type="text/css" /> <script src="js/jquery.min.js"></script>
<script src="js/jquery-ui-1.8.16.custom.min.js"></script> <style>
body {
padding-top: 40px;
}
#main {
margin-top: 80px;
} .textalignright {
text-align: right;
} .marginbottom10 {
margin-bottom: 10px;
}
#newtodo_window {
text-align: left;
display: none;
}
</style> <script>
$(document).ready(function() {
$("#todolist").accordion({
collapsible: true
});
$(".datepicker").datepicker();
$('#newtodo_window').dialog({
autoOpen: false,
height: 'auto',
width: 'auto',
modal: true
});
$('#newtodo').click(function() {
$('#newtodo_window').dialog('open');
});
});
</script>
</head>
<body>
<div class="topbar">
<div class="fill">
<div class="container">
<a class="brand" href="index.php">SimpleTODO</a>
</div>
</div>
</div>
<div id="main" class="container">
<div class="textalignright marginbottom10">
<span id="newtodo" class="btn info">Create a new TODO item</span>
<div id="newtodo_window" title="Create a new TODO item">
<form method="POST" action="new_todo.php">
<p>Title:<br /><input type="text" class="title" name="title" placeholder="TODO title" /></p>
<p>Date Due:<br /><input type="text" class="datepicker" name="due_date" placeholder="MM/DD/YYYY" /></p>
<p>Description:<br /><textarea class="description" name="description"></textarea></p>
<div class="actions">
<input type="submit" value="Create" name="new_submit" class="btn primary" />
</div>
</form>
</div>
</div>
<div id="todolist">
<?php foreach($todo_items as $todo): ?>
<h3><a href="#"><?php echo $todo->title; ?></a></h3>
<div>
<form method="POST" action="update_todo.php">
<div class="textalignright">
<a href="delete_todo.php?todo_id=<?php echo $todo->todo_id; ?>">Delete</a>
</div>
<div>
<p>Date Due:<br /><input type="text" id="datepicker_<?php echo $todo->todo_id; ?>" class="datepicker" name="due_date" value="12/09/2011" /></p>
<p>Description:<br /><textarea class="span8" id="description_<?php echo $todo->todo_id; ?>" class="description" name="description"><?php echo $todo->description; ?></textarea></p>
</div>
<div class="textalignright">
<?php if( $todo->is_done == 'false' ): ?>
<input type="hidden" value="false" name="is_done" />
<input type="submit" class="btn" value="Mark as Done?" name="markasdone_button" />
<?php else: ?>
<input type="hidden" value="true" name="is_done" />
<input type="button" class="btn success" value="Done!" name="done_button" />
<?php endif; ?>
<input type="hidden" value="<?php echo $todo->todo_id; ?>" name="todo_id" />
<input type="hidden" value="<?php echo $todo->title; ?>" name="title" />
<input type="submit" class="btn primary" value="Save Changes" name="update_button" />
</div>
</form>
</div>
<?php endforeach; ?>
</div>
</div>
</body>
</html>
这段代码的运行结果如下:
很酷哈?但它目前啥也干不了,那么让我们开始添加一些功能吧。我将为new_todo.php提供代码,它们调用todo/createAPI调用来创建新的TODO项。创建其他页(update_todo.php和delete_todo.php)应该与此十分相似,因此我把它们留给你。打开new_todo.php,然后把下面的代码添进去:
<?php
session_start();
include_once 'apicaller.php'; $apicaller = new ApiCaller('APP001', '28e336ac6c9423d946ba02d19c6a2632', 'http://localhost/simpletodo_api/'); $new_item = $apicaller->sendRequest(array(
'controller' => 'todo',
'action' => 'create',
'title' => $_POST['title'],
'due_date' => $_POST['due_date'],
'description' => $_POST['description'],
'username' => $_SESSION['username'],
'userpass' => $_SESSION['userpass']
)); header('Location: todo.php');
exit();
?>
正如你所看到的,new_todo.php页再次使用了ApiCaller调用来简化向API服务器所发送的 todo/create请求。这主要完成了与之前相同的事情:
- 开启一个会话,以使其获得对存储于$_SESSION中的$username和$userpass的访问权
- 实例化一个新的ApiCaller类,为它提供APP ID, APP KEY,以及API服务器的URL
- 通过sendRequest()方法发送请求
- 重定向回todo.php
恭喜,它好用了!你已经成功地创建了一个以API为中心的应用!
结论
围绕API创建并开发应用具有如此之多的优势。想创建一个Android版的SimpleTODO?你需要的所有功能都已经在API服务器上了,所以你所 要做的就是创建客户端!想重构或者优化某些类?没问题——只要确保输出相同即可。想添加更多的功能?你可以在不影响任何客户端代码的前提下做到!
尽管存在着某些像是更长的开发时间或者更加复杂,但是以这种方式开发网络应用的优势却远比其劣势更重要。今天的这种开发由我们自己权衡取舍,从而使我们能够在将来获益。
你是准备使用一台API服务器作为你的下一个Web应用,还是已经在过去的项目中使用了相同的技术?请在评论中告知!
转载自:http://www.oschina.net/translate/creating-an-api-centric-web-application?from=20130818
译者:白金小熊 参与翻译:stoneyang, lwei, bigtiger02
创建以API为中心的Web应用(转)的更多相关文章
- 创建以 API 为中心的 Web 应用
http://www.oschina.net/translate/creating-an-api-centric-web-application?from=20130818 正计划着要开始搞一个新的网 ...
- ABP示例程序-使用AngularJs,ASP.NET MVC,Web API和EntityFramework创建N层的单页面Web应用
本片文章翻译自ABP在CodeProject上的一个简单示例程序,网站上的程序是用ABP之前的版本创建的,模板创建界面及工程文档有所改变,本文基于最新的模板创建.通过这个简单的示例可以对ABP有个更深 ...
- 使用JWT创建安全的ASP.NET Core Web API
在本文中,你将学习如何在ASP.NET Core Web API中使用JWT身份验证.我将在编写代码时逐步简化.我们将构建两个终结点,一个用于客户登录,另一个用于获取客户订单.这些api将连接到在本地 ...
- 【Java】Web 服务编程技巧与窍门: 在 UDDI 注册中心为 Web 服务注册开发 UDDI Java 应用程序
本技巧建立了一个使用统一描述.发现和集成 (Universal Description, Discovery, and Integration,UDDI) 来注册应用程序级消费的 Web 服务实例.作 ...
- ASP.NET Web API路由系统:Web Host下的URL路由
ASP.NET Web API提供了一个独立于执行环境的抽象化的HTTP请求处理管道,而ASP.NET Web API自身的路由系统也不依赖于ASP.NET路由系统,所以它可以采用不同的寄宿方式运行于 ...
- 【ASP.NET Web API教程】3 Web API客户端
原文:[ASP.NET Web API教程]3 Web API客户端 Chapter 3: Web API Clients 第3章 Web API客户端 本文引自:http://www.asp.net ...
- Knockout, Web API 和 ASP.Net Web Forms 进行简单数据绑定
使用Knockout, Web API 和 ASP.Net Web Forms 进行简单数据绑定 原文地址:http://www.dotnetjalps.com/2013/05/Simple-da ...
- Web API 2 入门——使用Web API与ASP.NET Web窗体(谷歌翻译)
在这篇文章中 概观 创建Web窗体项目 创建模型和控制器 添加路由信息 添加客户端AJAX 作者:Mike Wasson 虽然ASP.NET Web API与ASP.NET MVC打包在一起,但很容易 ...
- 创建ArcGIS API for JavaScript的第一个示例程序
原文:创建ArcGIS API for JavaScript的第一个示例程序 在上一篇博客中已经介绍了如何搭建ArcGIS API for JavaScript开发环境,如果您还没有搭建好开发环境的话 ...
随机推荐
- Installing .NET Core on Ubuntu-摘自网络
Installing .NET Core on Linux By Zlatko Knezevic These instructions will lead you through acquiring ...
- php利用phpexcel导出数据
php中利用phpexcel导出数据的实现代码.对phpexcel类库不熟悉的朋友,可以阅读下<phpexcel中文帮助手册>中的内容,具体实例大家可以phpexcel快速开发指南中的相关 ...
- mysql执行计划介绍
简单讲讲mysql的执行计划,只列出了一些常见的情况,希望对大家有所帮助 烂sql不仅直接影响sql的响应时间,更影响db的性能,导致其它正常的sql响应时间变长.如何写好sql,学会看执行计划至 ...
- [na]802.1x协议无线认证协议&dot1x有线认证实验
以前搞无线时候,会涉及到无线client接入方式的认证协议. 认证方式+加密方式+有线的dot1x. 注:以前都是doc粘贴到博客的,加上没写博客的习惯,因此会比较乱. EAP(扩展认证协议)是什么? ...
- [na]mail收发过程
以前老记不住这smtp和pop3谁收谁发. 简单邮件传输协议(SMTP),用来发送或中转发出的电子邮件, 占用tcp 25端口. 第三版邮局协议(POP3),用于将服务器上把邮件存储到本地 ...
- angular学习笔记(二)-创建angular模块
如果在页面的html标签(或任意标签)中添加ng-app,表示对整个页面应用angular来管理. 他是一个模块. 模块有助于把东西从全局命名空间中隔离. 今天学习如何自定义创建模块: <!DO ...
- 简单的图形学(三)——光源
参考自:用JavaScript玩转计算机图形学(二)基本光源 - Milo Yip - 博客园,主要讲述三种最基本的光源--平行光.点光源.聚光灯,其实就是三种数学模型. 代码的调整 先前的代码中,颜 ...
- electron-vue 项目搭建的地址
https://simulatedgreg.gitbooks.io/electron-vue/content/en/ 现在的网址:vue的electron的文件: https://github.com ...
- eclipse 项目中的java文件没有在WEB-INF目录下的classes中 生成相对应的编译后的类
1.首先确定project->Build Automatically是否勾选上: 2.执行完第一步之后测试一下看是否能编译,如果还是不能,则进行手动编译: 3,进入clean对话框,选择Cle ...
- maven导入外部包pom.xml配置
<dependency> <groupId>com.hadoop</groupId> <artifactId>hadoop-lzo</artifa ...