python 请求服务器的实现代码(http请求和https请求)

时间:2021-05-22

一、http请求

1、http请求方式:get和post

get一般用于获取/查询资源信息,在浏览器中直接输入url+请求参数点击enter之后连接成功服务器就能获取到的内容,post请求一般用于更新资源,通过form表单或者json、xml等其他形式提交给服务器端,然后等待服务器端给返回一个结果的方式(这个返回结果一般就是被修改之后的是否成功的状态,或者是修改后的最新数据table等)。

http请求,不论是get还是post请求,都会包含几个部分,分别是header,cookie,get会有param,post会有body。

这个可以通过fiddler里面抓包就可以拿到需要的Headers,一般需要设置的值可能有:

header = { "Host": "x.x.360.cn", "Authorization": "Basic: someValue", "Content-Type": r"application/json", "Connection": "keep-alive", "Proxy-Connection": "keep-alive", "Cookie": "xxxxxxxxx(备注:这里的具体值请自行填写,其他key对应的值也是一样)", "User-Agent": "360xxxxxx(备注:这里的信息也请自行抓到之后填写,不需要的话,可以不用填写)" }

针对正式环境和测试环境需要设置url的地址,以及Header的"Host"中的具体域名的方法如下:

(1)正式环境:url中的host也设置成域名,比如:http://%s/search/searchList的%s就替换成 域名,在headers中的"HOST"的键对应的value也是域名,比如说都是"x.y.360.cn"

(2)测试环境: url中的host设置成具体的IP,比如:http://%s/search/searchList的%s就替换成 10.108.225.234这样的具体IP(备注,这个IP就是你们平时开发上测试代码的机器),但是headers中的"HOST"的键对应的value必须得写成域名,比如"x.y.360.cn"

原因:因为一个IP地址对应的服务器上可能会有多个域名,因为可能会上多个不同业务的服务器代码,如此会有一个默认的域名,但是并不一定是你的这个业务对应的域名,所以一定要在headers中的"HOST"中指定域名才可以找到这个域名,从而找到其对应的接口,进行正确的调用。

进一步,对于一个IP地址对应的服务器,其上会有很多域名,这个是如何部署的呢?需要问一下服务器端的同学,比如说会有x.360.cn和x.y.360.cn,这个是如何进行配置的呢?具体原因是使用了nginx的配置:https://:80")>>> conn.request("POST", "/cgi-bin/query", params, headers)>>> response = conn.getresponse()>>> print response.status, response.reason200 OK>>> data = response.read()>>> conn.close()

备注:以上代码也是运行不通过的,因为是比较久远的python版本的例子,主要需要注意的是:需要自己设置headers,在其中根据需要传递Cookie、Content-Type、Accept等信息,通过key-value的形式传递,具体的body中传递的信息,要注意是json格式的,还是通过urlencode编码等,格式一定要跟开发沟通清楚,否则会有错误请求的问题,之后得到response,并获取response的status、body、headers就与前面的"GET"method一样了。

(2)request库

request库是python的第三方库,官方文档地址:http://www.python-requests.org/en/master/user/quickstart/#make-a-request

get请求:

>>> r = requests.get('http://httpbin.org/get')>>> r<Response [200]>>>> r.textu'{\n "args": {}, \n "headers": {\n "Accept": "**", \n "Accept-Encoding": "gzip, deflate", \n "Content-Length": "9", \n "Content-Type": "application/x-www-form-urlencoded", \n "Host": "httpbin.org", \n "User-Agent": "python-requests/2.9.1"\n }, \n "json": null, \n "origin": "218.30.116.185", \n "url": "http://httpbin.org/post"\n}\n'

我这里用的还是httplib的,request的后续有详细使用教程会补充上来。

二、https请求

1、https的请求方式:get和post

http和https的区别:

(1)url的前面是https://而不是http://,使用ssl进行加密/身份认证,并且http的默认端口是80,https的默认端口是443。

(2)因为有ssl的认证和加密,所以具体的底层的通信过程中会有不同,https的这一层在建立连接的时候,需要设置socket属性,socket属性的生成需要使用具体的方法调用,方法调用的参数需要指定:ca_certs=服务器端给提供的公钥证书即可。

然后如果还有客户端认证的话,那客户端也可以提供出自己的key_file,cert_file。

什么是ssl?

ssl的全称是(Secure Sockets Layer)安全套接层,另外还有TLS(Transport Layer Secure,传输层安全),这两种协议都是为网络提供安全和数据完整性的一种安全协议,在传输层对网络连接进行加密。

为什么要用这个?

防止数据以及网络连接的传输内容被截获,所以涉及到个人或者重要的信息等,都需要进行建立ssl连接,通过https的请求方式加密处理。

2、https请求端口、ssl建立,以及实现具体的get和post请求

post请求:

httpsConn = None try: httpsConn = httplib.HTTPSConnection(host) sock = socket.create_connection((httpsConn.host, httpsConn.port)) try: httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_SSLv3) #self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv3) except ssl.SSLError, e: print("Trying SSLv3.") try: httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_SSLv23) #self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv23) except ssl.SSLError, e: print("Trying SSLv23.") try: httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLSv1) except ssl.SSLError, e: print("Trying TLSv1.") try: httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_SSLv2) except ssl.SSLError, e: print("Trying SSLv2.") httpsConn.request("POST", path, body, headers) res = httpsConn.getresponse() headers = {} for k, v in res.getheaders(): headers[k] = v return res.status, headers, res.read() except Exception, e: import traceback print traceback.format_exc() return e finally: if httpsConn: httpsConn.close

备注:

因为是客户端证书,所以没有使用注释的代码:#self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv3),这个程序中需要指定客户端的私钥密钥的文件,如果只有服务器端有私钥,客户端有公钥,则客户端的程序需要指定公钥文件,见代码:httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_SSLv3),是通过ca_certs参数指定的,CERT_FILE是文件的路径,保证能够找到即可;如果是是一个文件夹下有多个文件,然后这多个文件都是需要用到的,比如A域名的证书和B域名的证书,A服务器在对接口处理请求的时候,会向B端发请求,如此客户端需要将A域名证书和B域名证书都添加进来,所以只要把文件夹路径设置成ca_certs参数的值即可。

另外,如果不确定SSL的版本,则需要尝试多个不同的SSL版本:ssl.PROTOCOL_TLSv1、ssl_version=ssl.PROTOCOL_SSLv2、ssl_version=ssl.PROTOCOL_SSLv23、ssl_version=ssl.PROTOCOL_SSLv3。

get请求的话,就将httpsConn.request("POST", path, body, headers)中的"POST"换成"GET"就好了,然后body设置为None即可。

3、ssl建立的过程中需要使用的证书(证书格式、证书生成、证书转换)、什么是服务器端/客户端校验?私钥公钥的概念

服务器端会有私钥和公钥,公钥会拿出来提供给客户端,在python的具体程序中,分别是key_file和cert_file,其中cert_file要提供给客户端。

python-cookbook中对建立ssl的连接的讲解见:http://python3-cookbook.readthedocs.io/zh_CN/latest/c11/p10_add_ssl_to_network_services.html :

以下是服务器端代码:

from socket import socket, AF_INET, SOCK_STREAMimport sslKEYFILE = 'server_key.pem' # Private key of the serverCERTFILE = 'server_cert.pem' # Server certificate (given to client)def echo_client(s): while True: data = s.recv(8192) if data == b'': break s.send(data) s.close() print('Connection closed')def echo_server(address): s = socket(AF_INET, SOCK_STREAM) s.bind(address) s.listen(1) # Wrap with an SSL layer requiring client certs s_ssl = ssl.wrap_socket(s, keyfile=KEYFILE, certfile=CERTFILE, server_side=True ) # Wait for connections while True: try: c,a = s_ssl.accept() print('Got connection', c, a) echo_client(c) except Exception as e: print('{}: {}'.format(e.__class__.__name__, e))echo_server(('', 20000))

之后是客户端连接服务器端的例子:

>>> from socket import socket, AF_INET, SOCK_STREAM>>> import ssl>>> s = socket(AF_INET, SOCK_STREAM)>>> s_ssl = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs = 'server_cert.pem')>>> s_ssl.connect(('localhost', 20000))>>> s_ssl.send(b'Hello World?')12>>> s_ssl.recv(8192)b'Hello World?'>>>

备注:其中 ssl.wrap_socket(s,cert_reqs=ssl.CERT_REQUIRED,ca_certs = 'server_cert.pem') 的ca_certs就是需要在客户端指定的证书,这个是服务器给的公钥证书。

证书的格式:一般有der格式、pem格式,且格式不能单纯通过后缀名去进行判定,比如一个后缀名是crt,就认为其不是pem的格式是错误的。

证书转换:讲解证书转换的url地址:http://netkiller.github.io/cryptography/openssl/format.html

可以通过OpenSSL(OpenSSL的安装:https://www.jb51.net/softjc/575021.html)来生成证书、以及进行证书的格式转换,比如将der转成pem格式,或者将pem转成der格式的。如果你不确定你的证书的格式,可以将两种转换都尝试一下,因为如果原本就是pem格式的,希望通过der转成pem格式的命令调用之后,会有错误产生。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章