全部产品

1. 创建服务和编写函数

更新时间:2019-05-31 14:45:37

本文用函数 A 实现需要访问具有访问控制的服务,用函数 B 实现具有访问控制的第三方服务。

  • 函数 A 使用 HTTP 触发器,接收外部用户实际请求,并在处理请求过程中访问函数 B 尝试获取受保护数据,如果获得该数据,则进行进一步处理操作,否则不进行特定操作。

  • 函数 B 在这里同样使用 HTTP 触发器。B 利用白名单校验来访者,如果来访者通过校验则返回请求的资源,否则返回鉴权失败。

  • 代理服务器使用 ECS 搭建,直接利用 Nginx 进行服务代理。

在服务 A 与服务 B 中创建函数

  1. 分别对 A 和 B 新建立两个服务,在左侧导航栏选择,分别进入到新建的服务中。
  2. 单击 【创建函数】,在创建函数页面:
    1. 单击 【选择全部的语言】,在下拉菜单中选择 Python2.7(本示例代码基于 Python )。
    2. 选择 【空白函数】。
    3. 选择【不创建触发器】。
    4. 创建函数并填写所在服务、函数名称、描述信息和运行环境信息。
    5. 单击【下一步】。
    6. 核对信息无误后,单击【创建】。
  3. 编写代码。
    1. 对于函数 A ,采用最简单的 HTTP 触发器方式建立,代码可直接 copy 下述内容并在控制台上提交保存。
    2. 对于函数 B ,使用了 Django 框架实现,因此可采用命令行工具 fcli 或 PythonSDK 上传代码包,也可使用 OSS 或 zip 包直接上传。
  4. 对 A 和 B 中的函数分别构建 HTTP 触发器。

在创建或搭建过程中如遇困难可参考这里的详情:

至此,我们的服务就搭建完成了。因为 B 中的白名单只添加了代理服务器的公网 IP,此时 A 中直接调用 B 是无法获取授权的。下面,我们具体看下各个函数的内容。

编写函数 A

函数 A 直接采用普通的HTTP触发器触发。

编写函数

函数说明:

  • handler 为函数调用入口,主要为业务逻辑,在这里分别模拟了不经过代理调用函数 B 及经过代理调用函数 B 的调用结果。
  • get_data_by_url 主要封装了请求函数 B 数据的业务逻辑。
  • my_http_request 实现了利用代理发送 HTTP 请求的方式。
  1. # -*- coding: utf-8 -*-
  2. import logging
  3. import urllib, urllib2, sys
  4. import ssl
  5. import json
  6. # 代理服务地址
  7. proxy_address = 'ip:port'
  8. # 函数 B 服务地址
  9. data_service_host = 'https://{id}.{region}.fc.aliyuncs.com'
  10. data_service_path = '/service/path'
  11. def handler(environ, start_response):
  12. """
  13. entrance
  14. """
  15. url = data_service_host + data_service_path
  16. # 使用代理访问
  17. proxy_result = get_data_by_url(url, proxy_address)
  18. # 不使用代理访问
  19. normal_result = get_data_by_url(url, None)
  20. # 展示用,直接将两种情况的返回拼接后展示出来
  21. result = {
  22. "query_with_proxy_result": proxy_result,
  23. "query_without_proxy_result": normal_result
  24. }
  25. status = '200 OK'
  26. response_headers = [('Content-type', 'text/json')]
  27. start_response(status, response_headers)
  28. return json.dumps(result)
  29. def get_data_by_url(url, proxy):
  30. """
  31. 用户数据服务访问封装
  32. """
  33. result = {
  34. "success": False,
  35. "secret_data": '',
  36. "data_service_raw_data": {}
  37. }
  38. content = my_http_request(url, proxy)
  39. if content:
  40. content = json.loads(content)
  41. result["data_service_raw_data"] = content
  42. # 模拟访问后数据处理
  43. if "authorized" in content and content["authorized"]:
  44. result["success"] = True
  45. result["secret_data"] = content["protected_data"]
  46. return result
  47. def my_http_request(url, proxy=None):
  48. """
  49. 带proxy的网络请求
  50. """
  51. try:
  52. ret = None
  53. socket_fd = None
  54. request = urllib2.Request(url)
  55. request.add_header('User-Agent', 'Fake_browser/1.0')
  56. if proxy:
  57. request.set_proxy(proxy, 'http')
  58. opener = urllib2.build_opener()
  59. socket_fd = opener.open(request)
  60. ret = socket_fd.read()
  61. except Exception as e:
  62. ret = json.dumps({"info": "exception in proxy query: %s" % e})
  63. finally:
  64. if socket_fd:
  65. socket_fd.close()
  66. return ret

编写函数 B

函数 B 我们采用 Django 搭建了一个 Web 服务,服务中使用白名单设置进行鉴权,通过后返回相应数据。代码结构如下:

  1. project/
  2. ├── lib
  3. ├── Django-1.11.13.dist-info
  4. ├── django
  5. ├── pytz
  6. └── pytz-2018.4.dist-info
  7. ├── main.py
  8. └── src
  9. ├── __init__.py
  10. ├── bin
  11. ├── __init__.py
  12. └── manage.py
  13. ├── conf
  14. ├── __init__.py
  15. ├── settings.py
  16. ├── urls.py
  17. └── wsgi.py
  18. ├── data
  19. └── views
  20. ├── __init__.py
  21. └── view.py

以下章节为Django代码示例。

编写函数

函数入口:

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. import sys
  4. import os
  5. # load local django
  6. sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + '/lib')
  7. sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "src"))
  8. import django
  9. print (django.__version__)
  10. import views.view
  11. from conf.wsgi import application
  12. def handler(environ, start_response):
  13. import urlparse
  14. parsed_tuple = urlparse.urlparse(environ['fc.request_uri'])
  15. li = parsed_tuple.path.split('/')
  16. global base_path
  17. if not views.view.base_path:
  18. views.view.base_path = "/".join(li[0:5])
  19. return application(environ, start_response)

urls.py:

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from views import view
  4. urlpatterns = [
  5. url(r'^index$', view.index),
  6. url(r'^get_data$', view.get_data),
  7. ]

views.py:

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. from django.http import HttpResponse
  4. from django.conf import settings
  5. import logging
  6. import json
  7. logger = logging.getLogger()
  8. base_path = ""
  9. def index(request):
  10. """
  11. 测试入口
  12. """
  13. logger.info("Django request detected! url: index")
  14. white_list = settings.WHITE_LIST
  15. allowed_hostlist = ' '
  16. for allowed_host in white_list:
  17. allowed_hostlist += allowed_host
  18. allowed_hostlist += ' '
  19. return HttpResponse("<h1>It works! Copyright: jianyi</h1> White list: %s" % allowed_hostlist, status=200)
  20. def get_data(request):
  21. """
  22. 数据获取接口
  23. """
  24. result = {
  25. "remote_ip": '',
  26. "white_list": [],
  27. "authorized": False,
  28. "protected_data": ''
  29. }
  30. if request.META.has_key('HTTP_X_FORWARDED_FOR'):
  31. remote_ip = request.META['HTTP_X_FORWARDED_FOR']
  32. else:
  33. remote_ip = request.META['REMOTE_ADDR']
  34. result["remote_ip"] = remote_ip
  35. result["white_list"] = settings.WHITE_LIST
  36. if remote_ip in result["white_list"]:
  37. result["authorized"] = True
  38. result["protected_data"] = "Alibaba"
  39. return HttpResponse(json.dumps(result), status=200)

settings.py:在默认的 settings.py 文件结尾增加白名单配置:白名单中添加代理服务器的公网 IP 。

  1. # User conf
  2. WHITE_LIST = [
  3. "127.0.0.1",
  4. "xx.xx.xx.xx"
  5. ]

搭建代理步骤

在这里我们直接使用 Nginx 进行了服务的代理。Nginx 可以部署到 ECS 中,也可以部署到普通服务器上。Nginx 的编译安装可直接在网上搜索或参考这里安装后,配置文件代理部分可简单配置如下:

  1. server{
  2. resolver x.x.x.x;
  3. listen 8080;
  4. location / {
  5. proxy_pass http://$http_host$request_uri;
  6. }
  7. }

注意

  • 不能有 hostname
  • 必须有 resolver( dns ),即上面的x.x.x.x,换成你们的 DNS 服务器 ip 即可。
  • $http_host 和 $request_uri 是 nginx 系统变量,不要想着替换他们,保持原样就 OK。
  • 在实际生产环境中,我们建议搭建负载均衡集群(利用 nginx 、keepalived 等)及代理服务器集群进行代理服务,以提高系统可用性及整体性能。

查看dns方法:

  1. cat /etc/resolv.conf

上传函数 A 、B 的代码并配置好触发器,并启动代理 Nginx ,我们就可以开始进行测试了。

下一步

测试过程及结论