HTTPS導致的HTTP協議升級
依稀還記得大約兩年前搞過一手Nginx加殼打造https的操作,裏面涉及ws協議自動升級到wss。
如今又遇到https下http的協議自動升級成https的情況,如果頁面是https的,那麼頁面內容中http地址協議會自動升級到https,最容易遇到的,也是我遇到的問題是html頁面上img標籤的src,圖片路徑是http的,但是我們頁面的協議是https,導致這個圖片的協議直接重http升級到https,然後圖片的就訪問不到了。
解決這個問題比較簡單,最容易的方式就是直接把圖片服務器給搞成HTTPS,然後問題就解決了,好了,就寫到這兒吧?
當然,既然來了, 就要扯會兒犢子。
項目中你會遇到對接外部系統吧?那如果這個對象存儲服務是對方的,你沒辦法控制,別個就要用http,那這個時候就得我們自己出手了,其實也很簡單。
我們首先要明白的就是如何把這個http給他換成https就好了,也就是說我們頁面上要通過https去訪問到別人的http的對象服務器拿資源,我想正常有開發經驗的人很直接就能想到走代理,哈哈,如果你看過我那篇<通過Nginx加殼打造https>的文章,我想這個問題對你來講很簡單了。
解決這個問題有很多種方式,我列舉一下我處理過的幾種,都是沒有問題的。
1. nginx,nginx套殼,前端https打到nginx, nginx通過http代理到target
2. 如果是k8s, k8s增加service和自定義的endPoints(這個endPoints指向target), 通過traefik或者其他負載均衡工具直接增加新的https的域名規則,通過service, endPoints打出去
3. 前兩種在target爲域名時不會存在問題,但是如果是多IP的情況,就稍微有點點麻煩,但還是能解決問題。
3.1 通用型,直接部署代理服務,類似對象存儲的回源操作,內部部署一個https的代理服務,接口入參爲需要代理的圖片地址http://xxx/xx.jpg, 代理服務拉取圖片信息,然後直接返回
3.2 demo, https://domain.com/proxy?url=http://xxx/xx.jpg,代理服務拿到參數url,訪問並返回內容
第三種方式雖然方便,但是需要多部署一個服務,適當選擇吧,各有優勢,如果對方IP固定,那我認爲第二種是最簡單,最快速的。我們目前也是用的這種方式。如果有自己的域名,那我任務nginx代理最簡單,如果最求通用,那就第三種吧,到哪裏都能用。
第一種加殼代理的我就不解釋了,和之前打造https類似。
K8S Service
這個玩意兒比較簡單,不好演示得,懂的都懂,我貼個配置吧。
比如圖片地址是http://123.123.123.123:8882/xxx/xxx.png
k8s yaml資源文件
kind: Service
metadata:
name: obj-proxy
namespace: xxx
labels:
k8s-app: obj-proxy
spec:
type: ClusterIP
clusterIP: None
ports:
- name: port
port: 3102 ## service的集羣端口
protocol: TCP
---
apiVersion: v1
kind: Endpoints
metadata:
name: obj-proxy
namespace: xxx
labels:
k8s-app: obj-proxy
subsets:
- addresses:
- ip: 123.123.123.123 ## 目標服務地址
nodeName: 123.123.123.123
ports:
- name: port
port: 8882 ## 目標端口
protocol: TCP
traefik的規則部分
- kind: Rule
match: Host(`www.inner.com`) && PathPrefix(`/`)
services:
- name: obj-proxy ## 指向上面的service
namespace: xxx ## service所在的命名空間
port: 3102 ## service的端口
我們通過內部域名https://www.inner.com打到traefik,traefik根據這個路由規則,打到叫做obj-proxy
的service,然後service從它對應的endPoints指定的目標地址(123.123.123.123)打出去,看吧,是不是跟nignx加差不多,只是方式變了而已。
代理鏡像構建
這裏簡單來操作一下第三種方式,代理服務隨便寫,java,go等等都可以,主要邏輯就是拿到圖片的url,然後獲取到圖片流,返回,是不是很簡單?我屬實不想寫這玩意兒了,用個運維老大哥寫的python腳本吧(感謝某某運維老大哥),嘻嘻。
程序代理的python腳本
pyproxy.py
from flask import Flask, abort, Response, request
import os
import requests
app = Flask(__name__)
app.config["DEBUG"] = False
file_obj = None
def generate(file_obj):
while True:
content = file_obj.raw.read(102400)
if content:
yield content
else:
break
@app.route('/proxy', methods=['GET'])
def download_file():
try:
url = request.args.get('url').encode('utf-8')
print(url)
filename = os.path.basename(url)
file_obj = requests.get(url, stream=True)
headers = file_obj.headers
s = Response(generate(file_obj), content_type=headers.get('Content-Type'))
for k, v in headers.items():
s.headers[k] = v
s.headers['Content-Disposition'] = "attachment; filename={}".format(filename)
return s
except Exception as e:
if file_obj is not None:
file_obj.close()
Response.close()
abort(404)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
Dockerfile
FROM rackspacedot/python37:32
RUN pip3 install requests flask
COPY pyproxy.py /pyproxy.py
CMD ["python3","/pyproxy.py"]
構建運行
[root@master1 pyproxy]# docker build -t pyproxy:v1 .
[root@master1 pyproxy]# docker run -p 8000:8000 pyproxy:v1
* Serving Flask app 'pyproxy' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on all addresses.
WARNING: This is a development server. Do not use it in a production deployment.
* Running on http://172.17.0.2:8000/ (Press CTRL+C to quit)
我就不去搭建https了,驗證一下這個服務正常吧。轉發一張OSChina的圖。
test.html
...
<img src="http://192.168.2.14:8000/proxy?url=https://oscimg.oschina.net/oscnet/up-3d152f8f91bd03bc979d17d6d398779c8b1.png"/>
...
圖太佔空間就不貼了,沒有問題的,已驗證。