《深入Python》-11. HTTP Web 服务

11. HTTP Web 服务

出处: http://www.woodpecker.org.cn/diveintopython/http_web_services/index.html

第 11 章 HTTP Web 服务

  • 11.1. 概览
  • 11.2. 避免通过 HTTP 重复地获取数据
  • 11.3. HTTP 的特性
    • 11.3.1. 用户代理 (User-Agent)
    • 11.3.2. 重定向 (Redirects)
    • 11.3.3. Last-Modified/If-Modified-Since
    • 11.3.4. ETag/If-None-Match
    • 11.3.5. 压缩 (Compression)
  • 11.4. 调试 HTTP web 服务
  • 11.5. 设置 User-Agent
  • 11.6. 处理 Last-Modified 和 ETag
  • 11.7. 处理重定向
  • 11.8. 处理压缩数据
  • 11.9. 全部放在一起
  • 11.10. 小结

11.1. 概览

在讲解如何下载 web 页和如何从 URL 解析 XML时,你已经学习了关于 HTML 处理和 XML 处理,接下来让我们来更全面地探讨有关 HTTP web 服务的主题。

简单地讲,HTTP web 服务是指以编程的方式直接使用 HTTP 操作从远程服务器发送和接收数据。如果你要从服务器获取数据,直接使用 HTTP GET;如果您想发送新数据到服务器,使用 HTTP POST。(一些较高级的 HTTP web 服务 API 也定义了使用 HTTP PUT 和 HTTP DELETE 修改和删除现有数据的方法。) 换句话说,构建在 HTTP 协议中的 “verbs (动作)” (GET, POST, PUT 和 DELETE) 直接映射为接收、发送、修改和删除等应用级别的操作。

这种方法的主要优点是简单,并且许多不同的站点充分印证了这样的简单性是受欢迎的。数据 (通常是 XML 数据) 能静态创建和存储,或通过服务器端脚本和所有主流计算机语言 (包括用于下载数据的 HTTP 库) 动态生成。调试也很简单,因为您可以在任意浏览器中调用网络服务来查看这些原始数据。现代浏览器甚至可以为您进行良好的格式化并漂亮地打印这些 XML 数据,以便让您快速地浏览。

HTTP web 服务上的纯 XML 应用举例:

  • Amazon API 允许您从 Amazon.com 在线商店获取产品信息。
  • National Weather Service (美国) 和 Hong Kong Observatory (香港) 通过 web 服务提供天气警报。
  • Atom API 用来管理基于 web 的内容。
  • Syndicated feeds 应用于 weblogs 和新闻站点中带给您来自众多站点的最新消息。

在后面的几章里,我们将探索使用 HTTP 进行数据发送和接收传输的 API,但是不会将应用语义映射到潜在的 HTTP 语义。(所有这些都是通过 HTTP POST 这个管道完成的。) 但是本章将关注使用 HTTP GET 从远程服务器获取数据,并且将探索几个由纯 HTTP web 服务带来最大利益的 HTTP 特性。

如下所示为上一章曾经看到过的 openanything 模块的更高级版本:

例 11.1. openanything.py

如果您还没有下载本书附带的样例程序, 可以 下载本程序和其他样例程序。

             import urllib2, urlparse, gzip
from StringIO import StringIOUSER_AGENT = 'OpenAnything/1.0 +http://diveintopython.org/http_web_services/'class SmartRedirectHandler(urllib2.HTTPRedirectHandler):    def http_error_301(self, req, fp, code, msg, headers):  result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers)              result.status = code                                return result                                       def http_error_302(self, req, fp, code, msg, headers):  result = urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers)              result.status = code                                return result                                       class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler):   def http_error_default(self, req, fp, code, msg, headers):result = urllib2.HTTPError(                           req.get_full_url(), code, msg, headers, fp)       result.status = code                                  return result                                         def openAnything(source, etag=None, lastmodified=None, agent=USER_AGENT):'''URL, filename, or string --> streamThis function lets you define parsers that take any input source(URL, pathname to local or network file, or actual data as a string)and deal with it in a uniform manner.  Returned object is guaranteedto have all the basic stdio read methods (read, readline, readlines).Just .close() the object when you're done with it.If the etag argument is supplied, it will be used as the value of anIf-None-Match request header.If the lastmodified argument is supplied, it must be a formatteddate/time string in GMT (as returned in the Last-Modified header ofa previous request).  The formatted date/time will be usedas the value of an If-Modified-Since request header.If the agent argument is supplied, it will be used as the value of aUser-Agent request header.'''if hasattr(source, 'read'):return sourceif source == '-':return sys.stdinif urlparse.urlparse(source)[0] == 'http':                                      # open URL with urllib2                                                     request = urllib2.Request(source)                                           request.add_header('User-Agent', agent)                                     if etag:                                                                    request.add_header('If-None-Match', etag)                               if lastmodified:                                                            request.add_header('If-Modified-Since', lastmodified)                   request.add_header('Accept-encoding', 'gzip')                               opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler())return opener.open(request)                                                 # try to open with native open function (if source is a filename)try:return open(source)except (IOError, OSError):pass# treat source as stringreturn StringIO(str(source))def fetch(source, etag=None, last_modified=None, agent=USER_AGENT):  '''Fetch data and metadata from a URL, file, stream, or string'''result = {}                                                      f = openAnything(source, etag, last_modified, agent)             result['data'] = f.read()                                        if hasattr(f, 'headers'):                                        # save ETag, if the server sent one                          result['etag'] = f.headers.get('ETag')                       # save Last-Modified header, if the server sent one          result['lastmodified'] = f.headers.get('Last-Modified')      if f.headers.get('content-encoding', '') == 'gzip':          # data came back gzip-compressed, decompress it          result['data'] = gzip.GzipFile(fileobj=StringIO(result['data']])).read()if hasattr(f, 'url'):                                            result['url'] = f.url                                        result['status'] = 200                                       if hasattr(f, 'status'):                                         result['status'] = f.status                                  f.close()                                                        return result

进一步阅读

  • Paul Prescod 认为纯 HTTP web 服务是 Internet 的未来。

假如说你想用 HTTP 下载资源,例如一个 Atom feed 汇聚。你不仅仅想下载一次;而是想一次又一次地下载它,如每小时一次,从提供 news feed 的站点获得最新的消息。让我们首先用一种直接而原始的方法来实现它,然后看看如何改进它。

例 11.2. 用直接而原始的方法下载 feed

           >>>import urllib
>>>data = urllib.urlopen('http://diveintomark.org/xml/atom.xml').read()    

          >>>print data
<?xml version="1.0" encoding="iso-8859-1"?>
<feed version="0.3"xmlns="http://purl.org/atom/ns#"xmlns:dc="http://purl.org/dc/elements/1.1/"xml:lang="en"><title mode="escaped">dive into mark</title><link rel="alternate" type="text/html" href="http://diveintomark.org/"/><-- rest of feed omitted for brevity -->
  • 11.3.1. 用户代理 (User-Agent)
  • 11.3.2. 重定向 (Redirects)
  • 11.3.3. Last-Modified/If-Modified-Since
  • 11.3.4. ETag/If-None-Match
  • 11.3.5. 压缩 (Compression)

这里有五个你必须关注的 HTTP 重要特性。

11.3.1. 用户代理 (User-Agent)

User-Agent 是一种客户端告知服务器谁在什么时候通过 HTTP 请求了一个 web 页、feed 汇聚或其他类型的 web 服务的简单途径。当客户端请求一个资源时,应该尽可能明确发起请求的是谁,以便当产生异常错误时,允许服务器端的管理员与客户端的开发者取得联系。

默认情况下 Python 发送一个通用的 User-AgentPython-urllib/1.15。下一节,您将看到更加有针对性的 User-Agent

11.3.2. 重定向 (Redirects)

有时资源移来移去。Web 站点重组内容,页面移动到了新的地址。甚至是 web 服务重组。原来位于 http://example.com/index.xml 的 feed 汇聚可能被移动到 http://example.com/xml/atom.xml。或者因为一个机构的扩展或重组,整个域被迁移。例如,http://www.example.com/index.xml 可能被重定向到 http://server-farm-1.example.com/index.xml

您每次从 HTTP 服务器请求任何类型的资源时,服务器的响应中均包含一个状态代码。状态代码 200 的意思是 “一切正常,这就是您请求的页面”。状态代码 404 的意思是 “页面没找到”。 (当浏览 web 时,你可能看到过 404 errors。)

HTTP 有两种不同的方法表示资源已经被移动。状态代码 302 表示临时重定向;这意味着 “哎呀,访问内容被临时移动” (然后在 Location: 头信息中给出临时地址)。状态代码 301 表示永久重定向;这意味着 “哎呀,访问内容被永久移动” (然后在 Location: 头信息中给出新地址)。如果您获得了一个 302 状态代码和一个新地址,HTTP 规范说您应该使用新地址获取您的请求,但是下次您要访问同一资源时,应该使用原地址重试。但是如果您获得了一个 301 状态代码和一个新地址,您应该从此使用新地址。

当从 HTTP 服务器接受到一个适当的状态代码时,urllib.urlopen 将自动 “跟踪” 重定向,但不幸的是,当它做了重定向时不会告诉你。 你将最终获得所请求的数据,却丝毫不会察觉到在这个过程中一个潜在的库 “帮助” 你做了一次重定向操作。因此你将继续不断地使用旧地址,并且每次都将获得被重定向的新地址。这一过程要往返两次而不是一次:太没效率了!本章的后面,您将看到如何改进这一点,从而适当地且有效率地处理永久重定向。

11.3.3. Last-Modified/If-Modified-Since

有些数据随时都在变化。CNN.com 的主页经常几分钟就更新。另一方面,Google.com 的主页几个星期才更新一次 (当他们上传特殊的假日 logo,或为一个新服务作广告时)。 Web 服务是不变的:通常服务器知道你所请求的数据的最后修改时间,并且 HTTP 为服务器提供了一种将最近修改数据连同你请求的数据一同发送的方法。

如果你第二次 (或第三次,或第四次) 请求相同的数据,你可以告诉服务器你上一次获得的最后修改日期:在你的请求中发送一个 If-Modified-Since 头信息,它包含了上一次从服务器连同数据所获得的日期。如果数据从那时起没有改变,服务器将返回一个特殊的 HTTP 状态代码 304,这意味着 “从上一次请求后这个数据没有改变”。这一点有何进步呢?当服务器发送状态编码 304 时,不再重新发送数据。您仅仅获得了这个状态代码。所以当数据没有更新时,你不需要一次又一次地下载相同的数据;服务器假定你有本地的缓存数据。

所有现代的浏览器都支持最近修改 (last-modified) 的数据检查。如果你曾经访问过某页,一天后重新访问相同的页时发现它没有变化,并奇怪第二次访问时页面加载得如此之快——这就是原因所在。你的浏览器首次 访问时会在本地缓存页面内容,当你第二次访问,浏览器自动发送首次访问时从服务器获得的最近修改日期。服务器简单地返回 304: Not Modified (没有修改),因此浏览器就会知道从本地缓存加载页面。在这一点上,Web 服务也如此智能。

Python 的 URL 库没有提供内置的最近修改数据检查支持,但是你可以为每一个请求添加任意的头信息并在每一个响应中读取任意头信息,从而自己添加这种支持。

11.3.4. ETag/If-None-Match

ETag 是实现与最近修改数据检查同样的功能的另一种方法:没有变化时不重新下载数据。其工作方式是:服务器发送你所请求的数据的同时,发送某种数据的 hash (在 ETag 头信息中给出)。hash 的确定完全取决于服务器。当第二次请求相同的数据时,你需要在 If-None-Match: 头信息中包含 ETag hash,如果数据没有改变,服务器将返回 304 状态代码。与最近修改数据检查相同,服务器仅仅 发送 304 状态代码;第二次将不为你发送相同的数据。在第二次请求时,通过包含 ETag hash,你告诉服务器:如果 hash 仍旧匹配就没有必要重新发送相同的数据,因为你还有上一次访问过的数据。

Python 的 URL 库没有对 ETag 的内置支持,但是在本章后面你将看到如何添加这种支持。

11.3.5. 压缩 (Compression)

最后一个重要的 HTTP 特性是 gzip 压缩。 关于 HTTP web 服务的主题几乎总是会涉及在网络线路上传输的 XML。XML 是文本,而且还是相当冗长的文本,而文本通常可以被很好地压缩。当你通过 HTTP 请求一个资源时,可以告诉服务器,如果它有任何新数据要发送给我时,请以压缩的格式发送。在你的请求中包含 Accept-encoding: gzip 头信息,如果服务器支持压缩,它将返回由 gzip 压缩的数据并且使用 Content-encoding: gzip 头信息标记。

Python 的 URL 库本身没有内置对 gzip 压缩的支持,但是你能为请求添加任意的头信息。Python 还提供了一个独立的 gzip 模块,它提供了对数据进行解压缩的功能。

注意我们用于下载 feed 汇聚的小单行脚本并不支持任何这些 HTTP 特性。让我们来看看如何改善它。

首先,让我们开启 Python HTTP 库的调试特性并查看网络线路上的传输过程。这对本章的全部内容都很有用,因为你将添加越来越多的特性。

例 11.3. 调试 HTTP

                     >>>import httplib
>>>httplib.HTTPConnection.debuglevel = 1             

                      >>>import urllib
>>>feeddata = urllib.urlopen('http://diveintomark.org/xml/atom.xml').read()
connect: (diveintomark.org, 80)                       

                     send: '
GET /xml/atom.xml HTTP/1.0                            

                     Host: diveintomark.org                                

                     User-agent: Python-urllib/1.15                        

                     '
reply: 'HTTP/1.1 200 OKrn'                          

                     header: Date: Wed, 14 Apr 2004 22:27:30 GMT
header: Server: Apache/2.0.49 (Debian GNU/Linux)
header: Content-Type: application/atom+xml
header: Last-Modified: Wed, 14 Apr 2004 22:14:38 GMT  

                     header: ETag: "e8284-68e0-4de30f80"                   

                       header: Accept-Ranges: bytes
header: Content-Length: 26848
header: Connection: close

改善你的 HTTP web 服务客户端的第一步就是用 User-Agent 适当地鉴别你自己。为了做到这一点,你需要远离基本的 urllib 而深入到 urllib2

例 11.4. urllib2 介绍

                                >>>import httplib
>>>httplib.HTTPConnection.debuglevel = 1                             

                              >>>import urllib2
>>>request = urllib2.Request('http://diveintomark.org/xml/atom.xml') 

                                >>>opener = urllib2.build_opener()                                   

                              >>>feeddata = opener.open(request).read()                            

                              connect: (diveintomark.org, 80)
send: '
GET /xml/atom.xml HTTP/1.0
Host: diveintomark.org
User-agent: Python-urllib/2.1
'
reply: 'HTTP/1.1 200 OKrn'
header: Date: Wed, 14 Apr 2004 23:23:12 GMT
header: Server: Apache/2.0.49 (Debian GNU/Linux)
header: Content-Type: application/atom+xml
header: Last-Modified: Wed, 14 Apr 2004 22:14:38 GMT
header: ETag: "e8284-68e0-4de30f80"
header: Accept-Ranges: bytes
header: Content-Length: 26848
header: Connection: close

既然你知道如何在你的 web 服务请求中添加自定义的 HTTP 头信息,接下来看看如何添加 Last-ModifiedETag 头信息的支持。

下面的这些例子将以调试标记置为关闭的状态来显示输出结果。如果你还停留在上一部分的开启状态,可以使用 httplib.HTTPConnection.debuglevel = 0 将其设置为关闭状态。或者,如果你认为有帮助也可以保持为开启状态。

例 11.6. 测试 Last-Modified

                                         >>>import urllib2
>>>request = urllib2.Request('http://diveintomark.org/xml/atom.xml')
>>>opener = urllib2.build_opener()
>>>firstdatastream = opener.open(request)
>>>firstdatastream.headers.dict                       

                                          {'date': 'Thu, 15 Apr 2004 20:42:41 GMT', 'server': 'Apache/2.0.49 (Debian GNU/Linux)', 'content-type': 'application/atom+xml','last-modified': 'Thu, 15 Apr 2004 19:45:21 GMT', 'etag': '"e842a-3e53-55d97640"','content-length': '15955', 'accept-ranges': 'bytes', 'connection': 'close'}
>>>request.add_header('If-Modified-Since',
...firstdatastream.headers.get('Last-Modified'))  

                                         >>>seconddatastream = opener.open(request)            

                                         Traceback (most recent call last):File "<stdin>", line 1, in ?File "c:python23liburllib2.py", line 326, in open'_open', req)File "c:python23liburllib2.py", line 306, in _call_chainresult = func(*args)File "c:python23liburllib2.py", line 901, in http_openreturn self.do_open(httplib.HTTP, req)File "c:python23liburllib2.py", line 895, in do_openreturn self.parent.error('http', req, fp, code, msg, hdrs)File "c:python23liburllib2.py", line 352, in errorreturn self._call_chain(*args)File "c:python23liburllib2.py", line 306, in _call_chainresult = func(*args)File "c:python23liburllib2.py", line 412, in http_error_defaultraise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
urllib2.HTTPError: HTTP Error 304: Not Modified

你可以使用两种不同的自定义 URL 处理器来处理永久重定向和临时重定向。

首先,让我们来看看重定向处理的必要性。

例 11.10. 没有重定向处理的情况下,访问 web 服务

                                                     >>>import urllib2, httplib
>>>httplib.HTTPConnection.debuglevel = 1           

                                                        >>>request = urllib2.Request(
...'http://diveintomark.org/redir/example301.xml') 

                                                        >>>opener = urllib2.build_opener()
>>>f = opener.open(request)
connect: (diveintomark.org, 80)
send: '
GET /redir/example301.xml HTTP/1.0
Host: diveintomark.org
User-agent: Python-urllib/2.1
'
reply: 'HTTP/1.1 301 Moved Permanentlyrn'             

                                                       header: Date: Thu, 15 Apr 2004 22:06:25 GMT
header: Server: Apache/2.0.49 (Debian GNU/Linux)
header: Location: http://diveintomark.org/xml/atom.xml  

                                                       header: Content-Length: 338
header: Connection: close
header: Content-Type: text/html; charset=iso-8859-1
connect: (diveintomark.org, 80)
send: '
GET /xml/atom.xml HTTP/1.0                              

                                                       Host: diveintomark.org
User-agent: Python-urllib/2.1
'
reply: 'HTTP/1.1 200 OKrn'
header: Date: Thu, 15 Apr 2004 22:06:25 GMT
header: Server: Apache/2.0.49 (Debian GNU/Linux)
header: Last-Modified: Thu, 15 Apr 2004 19:45:21 GMT
header: ETag: "e842a-3e53-55d97640"
header: Accept-Ranges: bytes
header: Content-Length: 15955
header: Connection: close
header: Content-Type: application/atom+xml
>>>f.url                                               

                                                     'http://diveintomark.org/xml/atom.xml'
>>>f.headers.dict
{'content-length': '15955',
'accept-ranges': 'bytes',
'server': 'Apache/2.0.49 (Debian GNU/Linux)',
'last-modified': 'Thu, 15 Apr 2004 19:45:21 GMT',
'connection': 'close',
'etag': '"e842a-3e53-55d97640"',
'date': 'Thu, 15 Apr 2004 22:06:25 GMT',
'content-type': 'application/atom+xml'}
>>>f.status
Traceback (most recent call last):File "<stdin>", line 1, in ?
AttributeError: addinfourl instance has no attribute 'status'

你要支持的最后一个重要的 HTTP 特性是压缩。许多 web 服务具有发送压缩数据的能力,这可以将网络线路上传输的大量数据消减 60% 以上。这尤其适用于 XML web 服务,因为 XML 数据 的压缩率可以很高。

服务器不会为你发送压缩数据,除非你告诉服务器你可以处理压缩数据。

例 11.14. 告诉服务器你想获得压缩数据

                                                                    >>>import urllib2, httplib
>>>httplib.HTTPConnection.debuglevel = 1
>>>request = urllib2.Request('http://diveintomark.org/xml/atom.xml')
>>>request.add_header('Accept-encoding', 'gzip')        

                                                                    >>>opener = urllib2.build_opener()
>>>f = opener.open(request)
connect: (diveintomark.org, 80)
send: '
GET /xml/atom.xml HTTP/1.0
Host: diveintomark.org
User-agent: Python-urllib/2.1
Accept-encoding: gzip                                    

                                                                  '
reply: 'HTTP/1.1 200 OKrn'
header: Date: Thu, 15 Apr 2004 22:24:39 GMT
header: Server: Apache/2.0.49 (Debian GNU/Linux)
header: Last-Modified: Thu, 15 Apr 2004 19:45:21 GMT
header: ETag: "e842a-3e53-55d97640"
header: Accept-Ranges: bytes
header: Vary: Accept-Encoding
header: Content-Encoding: gzip                           

                                                                  header: Content-Length: 6289                             

                                                                  header: Connection: close
header: Content-Type: application/atom+xml

你已经看到了构造一个智能的 HTTP web 客户端的所有片断。现在让我们看看如何将它们整合到一起。

例 11.17. openanything 函数

这个函数定义在 openanything.py 中。

                                                                             def openAnything(source, etag=None, lastmodified=None, agent=USER_AGENT):# non-HTTP code omitted for brevityif urlparse.urlparse(source)[0] == 'http':                                       

                                                                               # open URL with urllib2                                                     request = urllib2.Request(source)                                           request.add_header('User-Agent', agent)                                      

                                                                               if etag:                                                                    request.add_header('If-None-Match', etag)                                

                                                                                if lastmodified:                                                            request.add_header('If-Modified-Since', lastmodified)                    

                                                                                request.add_header('Accept-encoding', 'gzip')                                

                                                                              opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler()) 

                                                                             return opener.open(request)                                                  

openanything.py 及其函数现在可以完美地工作了。

每个客户端都应该支持 HTTP web 服务的以下 5 个重要特性:

  • 通过设置适当的 User-Agent 识别你的应用。
  • 适当地处理永久重定向。
  • 支持 Last-Modified 日期检查从而避免在数据未改变的情况下重新下载数据。
  • 支持 ETag hash 从而避免在数据未改变的情况下重新下载数据。
  • 支持 gzip 压缩从而在数据已经 改变的情况下尽可能地减少传输带宽。

《深入Python》-11. HTTP Web 服务相关推荐

  1. 【LINUX】——linux如何使用Python创建一个web服务

    问:linux如何使用Python创建一个web服务? 答:一句话,Python! 一句代码: /usr/local/bin/python -m SimpleHTTPServer 8686 > ...

  2. 通过python建立一个web服务查看服务器上的文本、图片、视频等文件

    通过python建立一个web服务查看服务器上的文本.图片.视频等文件 文章目录: 1 在服务器端开启一个服务 2 在本地浏览器中输入服务器的ip地址 1 在服务器端开启一个服务 python -m ...

  3. python restful django_如何使用Django / Python从RESTful Web服务中使用XML?

    我应该使用PyXML还是标准库中的内容? 解决方法: ElementTree是标准Python库的一部分. ElementTree是纯python,而cElementTree是更快的C实现: # Tr ...

  4. 如何使用Python Flask编写Web服务

    我们的许多客户正在使用我们的Webhook功能来构建有用的服务,但不幸的是,其他客户却没有. 我们经常听到他们的团队中没有人足够熟练地编写一种服务,该服务可以提取Webhook负载并处理数据. 这使得 ...

  5. Flask实现Web服务调用Python程序

    Flask实现Web服务调用Python程序 通过Web服务调用Python写的手写数字识别算法模型,得到手写数字识别结果. 项目场景: 项目需求:将客户端的请求经由Web服务器转发给Flask程序实 ...

  6. 保护REST API / Web服务的最佳实践[关闭]

    在设计REST API或服务时,是否存在处理安全性(身份验证,授权,身份管理)的最佳实践? 构建SOAP API时,您需要使用WS-Security作为指南,并且有很多关于该主题的文献. 我发现有关保 ...

  7. 怎么获取web开发怎么获取手机的唯一标识_PYTHON实现北京住宅小区数据抓取-(Web服务API-地点检索服务)

    最近工作需要整理了一些百度地图接口查询北京住宅小区的相关信息.该篇文章主要从如下3个方面的说明:Web服务API -地点检索服务.需求分析 和 PYTHON实现 . Web服务API -地点检索服务: ...

  8. 百度鹰眼html打开,BMap:WEB 服务API

    ylbtech-Map-Baidu: WEB 服务API 百度地图Web服务API为开发者提供http/https接口,即开发者通过http/https形式发起检索请求,获取返回json或xml格式的 ...

  9. go vs python 对接外部web api_python--web--让python提供api服务--aiohttp-Go语言中文社区

    aiohttp介绍 官网上有这样一句话介绍:Async HTTP client/server for asyncio and Python 翻译过来就是 基于asyncio和Python实现的异步HT ...

最新文章

  1. android重启软件用不了,应用程序重启而不是重启
  2. java基础学习(2)-java基本数据类型
  3. Mp3写入专辑图片(Kotlin)
  4. SpringBoot + Redis 解决海量重复提交问题
  5. 8-Python3从入门到实战—基础之数据类型(集合-Sets)
  6. 使用系统调用pipe建立一条管道线_使用Unixbench对服务器综合性能打分及测试结果...
  7. vb读出二进制文件,合并两个文件
  8. 【程序设计】变量和常量
  9. Java的序列化特性将要退出历史舞台了
  10. 艰难的时候总会过去,只要你能坚持下来~
  11. react-native 报错 RawText must be wrapped in an explicit Text component
  12. 【转】Elasticsearch+Django搜索引擎(一)
  13. c语言中期报告程序,课题中期报告
  14. cad高程测绘图lisp_CAD地形图高程信息快速提取的技术与实现
  15. 欧几里得算法及其证明
  16. IOS开发进阶学习资料(提升必备)
  17. ddwrt 扩张linux分区,FON2405e在引进自定义固件OpenWRTDDWRT.doc
  18. 解除win10防火墙对软件的误杀
  19. 路由器 RIP-2 配置
  20. 网站推广第一周总结和反思

热门文章

  1. 缓存的Cache Aside模式
  2. CentOS 6.7安装docker
  3. 使用nginx源代码编译安装lnmp
  4. JBOSS配置系统应用的端口号
  5. EM12C监控遇到 ‘cursor: pin S wait on X’ waits.
  6. alter system|session set events转储
  7. 500强公司面试的经典正确与错误回答对比!
  8. WINXP光启工具盘的制作(4)-acrosin true image
  9. python语言及其应用下载_Python语言及其应用 中文pdf完整版[13MB]
  10. 手机直播系统源码搭建说明