This topic shows you how to write code for a function that is assigned a public IP address in the Function Compute console.

Background information

In this topic, Function B is used to implement a third-party service configured with access control, and Function A is used to access the third-party service.

Procedure

  1. In the top navigation bar, select a region.
  2. Create Function A.
    1. Click Services and Functions. On the Services and Functions page, click Create Function.
    2. On the Create Function page, move the pointer over HTTP Function and click Configure and Deploy. Then, set the Service Name parameter.
      Note If the service whose name you specify does not exist, Function Compute automatically creates the service.
    3. Set the parameters for Function A and click Create.

      The sample code is written in Python. Therefore, select Python 2.7 from the Runtime drop-down list.

      Create Function A
    4. On the Code tab, select In-line Edit and enter the following code:
      -*- coding: utf-8 -*-
      import logging
      import urllib, urllib2, sys
      import ssl
      import json
      # The IP address of the proxy server.
      proxy_address = 'ip:port'
      # The endpoint of the third-party service that is implemented by Function B.
      data_service_host = 'https://{id}.{region}.fc.aliyuncs.com'
      data_service_path = '/service/path'
      def handler(environ, start_response):
          """
          entrance
          """
          url = data_service_host + data_service_path
          # Use the proxy to access the third-party service.
          proxy_result = get_data_by_url(url, proxy_address)
          # Do not use the proxy to access the third-party service.
          normal_result = get_data_by_url(url, None)
          # Merge and display the returned results in the two cases.
          result = {
              "query_with_proxy_result": proxy_result,
              "query_without_proxy_result": normal_result
          }
          status = '200 OK'
          response_headers = [('Content-type', 'text/json')]
          start_response(status, response_headers)
          return json.dumps(result)
      def get_data_by_url(url, proxy):
          """
          Encapsulate the service that accesses user data.
          """
          result = {
              "success": False,
              "secret_data": '',
              "data_service_raw_data": {}
          }
          content = my_http_request(url, proxy)
          if content:
            content = json.loads(content)
          result["data_service_raw_data"] = content
          # Process data after simulated access.
          if "authorized" in content and content["authorized"]:
              result["success"] = True
              result["secret_data"] = content["protected_data"]
          return result
      def my_http_request(url, proxy=None):
          """
          The network request that uses the proxy.
          """
          try:
              ret = None
              socket_fd = None
              request = urllib2.Request(url)
              request.add_header('User-Agent', 'Fake_browser/1.0')
              if proxy:
                  request.set_proxy(proxy, 'http')
              opener = urllib2.build_opener()
              socket_fd = opener.open(request)
              ret = socket_fd.read()
          except Exception as e:
              ret = json.dumps({"info": "exception in proxy query: %s" % e})
          finally:
              if socket_fd:
                  socket_fd.close()
          return ret          

      The following part describes the related functions:

      • handler is a function that Function Compute can invoke when Function Compute executes the code. It simulates the results of invoking Function B with and without using the proxy.
      • get_data_by_url contains the logic for invoking Function B.
      • my_http_request sends HTTP requests by using the proxy.
  3. Repeat the preceding steps to create Function B. On the Code tab, enter the following code.
    Note Function B is created by using Django. Therefore, you can use the command line tool fcli or SDK for Python to upload the code package. You can also use Object Storage Service (OSS) or directly upload a ZIP file.

    Function B has the following code structure:

    project/
    ├── lib
    │   ├── Django-1.11.13.dist-info
    │   ├── django
    │   ├── pytz
    │   └── pytz-2018.4.dist-info
    ├── main.py
    └── src
        ├── __init__.py
        ├── bin
        │   ├── __init__.py
        │   └── manage.py
        ├── conf
        │   ├── __init__.py
        │   ├── settings.py
        │   ├── urls.py
        │   └── wsgi.py
        ├── data
        └── views
              ├── __init__.py
              └── view.py            

    The following Django code provides an example:

    • Function handler:
      #! /usr/bin/env python
      # coding=utf-8
      import sys
      import os
      # load local django
      sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + '/lib')
      sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "src"))
      import django
      print (django.__version__)
      import views.view
      from conf.wsgi import application
      def handler(environ, start_response):
          import urlparse
          parsed_tuple = urlparse.urlparse(environ['fc.request_uri'])
          li = parsed_tuple.path.split('/')
          global base_path
          if not views.view.base_path:
              views.view.base_path = "/".join(li[0:5])
          return application(environ, start_response)            
    • urls.py:
      from django.conf.urls import url
      from django.contrib import admin
      from views import view
      urlpatterns = [
          url(r'^index$', view.index),
          url(r'^get_data$', view.get_data),
      ]           
    • views.py:
      #! /usr/bin/env python
      # coding=utf-8
      from django.http import HttpResponse
      from django.conf import settings
      import logging
      import json
      logger = logging.getLogger()
      base_path = ""
      def index(request):
          """
          Test the handler.
          """
          logger.info("Django request detected! url: index")
          white_list = settings.WHITE_LIST
          allowed_hostlist = ' '
      
          for allowed_host in white_list:
              allowed_hostlist += allowed_host
              allowed_hostlist += ' '
          return HttpResponse("<h1>It works! Copyright: jianyi</h1> White list: %s" % allowed_hostlist, status=200)
      def get_data(request):
          """
          Obtain the data.
          """
          result = {
              "remote_ip": '',
              "white_list": [],
              "authorized": False,
              "protected_data": ''
          }
          if request.META.has_key('HTTP_X_FORWARDED_FOR'):
              remote_ip = request.META['HTTP_X_FORWARDED_FOR']
          else:
              remote_ip = request.META['REMOTE_ADDR']
      
          result["remote_ip"] = remote_ip
          result["white_list"] = settings.WHITE_LIST
      
          if remote_ip in result["white_list"]:
              result["authorized"] = True
              result["protected_data"] = "Alibaba"
      
          return HttpResponse(json.dumps(result), status=200)           
    • settings.py:Add the whitelist setting to the end of the default settings.py file, and add the public IP address of the proxy server to the whitelist.
      # User conf
      WHITE_LIST = [
          "127.0.0.1",
          "xx.xx.xx.xx"
      ]           
  4. Configure a trigger. For more information, see Create a trigger.
  5. Build and start an NGINX proxy.

    You can deploy NGINX on an Elastic Compute Service (ECS) instance or a normal server. For more information, visit Install NGINX. After you install NGINX, you can configure the proxy settings in the configuration file based on the following sample code:

    server{
        resolver x.x.x.x;
        listen 8080;
        location / {
            proxy_pass http://$http_host$request_uri;
        }
    }           
    Notice
    • The proxy settings in the configuration file cannot contain the hostname parameter.
    • You must specify the IP address of your Domain Name System (DNS) server.
    • Do not change NGINX system variables $http_host and $request_uri.
    • In the production environment, we recommend that you use NGINX or Keepalived to build Server Load Balancer (SLB) clusters and proxy clusters to provide the proxy service. This improves the availability and performance of the system.

What to do next

Debug a function