1. 程式人生 > 其它 >使用nginx代理跨域,使用nginx代理bing的每日一圖

使用nginx代理跨域,使用nginx代理bing的每日一圖

前言

自從搞清楚了跨域原理後一直自鳴得意,感覺跨域沒啥問題了。而事實上對關於跨域的幾個header的理解也有限,但那又如何,我能做到跨域就行了。今天想把部落格背景圖改成bing的每日一圖,發現遇到跨域問題。首先想到的就是自己寫一個web,請求bing,然後傳出結果,把自己的介面允許跨域。確實做到了,但是。我找了一臺阿里雲伺服器,我安裝了java,我編寫了一個基於dropwizard的webservice。我需要寫指令碼去部署,確保系統穩定,掛了自動重啟。我要寫一堆的java程式碼來完成這件事。忽然想到nginx,於是一發不可收拾。

安裝好Nginx

參閱 http://blog.rmiao.top/install-nginx-on-centos/

找到配置檔案/usr/local/nginx/nginx.conf

新增代理路由

location ^~/proxy/bing/ {
    add_header 'Access-Control-Allow-Origin' 'http://localhost:8088';
    add_header 'Cache-Control' 'public, max-age=604800';

    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

    rewrite ^/proxy/bing/(.*)$ /$1 break;
    proxy_pass https://cn.bing.com/; 
}

瀏覽器訪問自動代理

http://101.200.218.760/proxy/bing/HPImageArchive.aspx?format=js&idx=0&n=1

代理物件為:
https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1

這是最簡單的實現方案,但缺點是隻能指定一個域名跨域。

如果我想增加多個origin怎麼辦

不要想用逗號隔開,這個不行,瀏覽器不允許。那麼只能自己判斷比較後插入一個合適的值。

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location / {
        root   html;
        index  index.html index.htm;
    }

    location ^~/proxy/bing/ {

        set $cors "local";

        if ( $http_referer ~* "(https?://www.cnblogs.com/woshimrf[^s]*)|(https?://api.rmiao.top[^s]*)|(https?://blog.rmiao.top[^s]*)|(http://localhost[^s]*)" ) {
            set $cors "allow";
        }

        if ( $request_method = "OPTIONS" ) {
            set $cors "${cors}options";
        }

        if ( $cors = "allowoptions" ) {
            add_header 'Access-Control-Allow-Origin' "$http_origin";
            add_header 'Access-Control-Allow-Credentials' "true";
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE';
            add_header 'Access-Control-Allow-Headers' 'reqid, nid, host, x-real-ip, x-forwarded-ip, event-type, event-id, accept, content-type';
            add_header 'Access-Control-Max-Age' 2592000;
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain, charset=utf-8';
            
            # indicate successful return with no content
            return 204;
        }
        
        if ($cors = "allow") {
            rewrite ^/proxy/bing/(.*)$ /pub_cors/$1 last;
        }

        if ($cors = "local") {
            return 403;
        }

    }

    location ^~/pub_cors/ {
        internal;
        # Tells the browser this origin may make cross-origin requests
        add_header 'Access-Control-Allow-Origin' "$http_origin";
        # in a preflight response, tells browser the subsequent actual request can include user credentials (e.g., cookies)
        add_header 'Access-Control-Allow-Credentials' "true";
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE';
        add_header 'Access-Control-Allow-Headers' 'reqid, nid, host, x-real-ip, x-forwarded-ip, event-type, event-id, accept, content-type';
        add_header 'Access-Control-Max-Age' 2592000;
        add_header 'Cache-Control' "public, max-age=604800";

        rewrite ^/pub_cors/(.*)$ /$1 break;
        proxy_pass https://cn.bing.com/; 
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }



}

語法要點就不推測了。後面有機會認真學習下。不過,這裡還是可以有幾個語法參考的。

  1. 設定變數 set $cors "local";
  2. 正則表示式 location ^~/proxy/bing/ {
  3. 獲取request的refer $http_referer
  4. 獲取request的method $request_method
  5. 獲取request的origin $http_origin
  6. 變數的讀取,包裹在引號裡也可以, add_header 'Access-Control-Allow-Origin' "$http_origin";
  7. 變數的讀取,可以用大括號包裹, set $cors "${cors}options";
  8. if 裡的判斷可以用正則, ~* 表示不區分大小寫,匹配正則, 取反!~*
  9. ~ 區分大小寫,匹配正則, 取反 !~
  10. 新增一個header, add_header 'Access-Control-Max-Age' 2592000;
  11. 設定option的預檢請求為204
  12. 跳轉, rewrite ^/proxy/bing/(.*)$ /pub_cors/$1 last;, 分3部分,第一部分是正則,是匹配當前location的url的正則。 第二部分是對映的值,在第二部分裡可以使用$1來獲得匹配第一個括號匹配的內容。
  13. if 裡的判斷可以用等號, if ($cors = "allow") {
  14. internal;是不是隻能內部訪問?
  15. 對於這種代理,尤其是bing這個,完全可以快取掉。 add_header 'Cache-Control' "public, max-age=604800";
  16. proxy_pass https://cn.bing.com/; 代理host,看樣子下一步請求的host就是它,對於rewrite ^/pub_cors/(.*)$ /$1 break;則是把匹配的$1拼接到host之後。即,完成了轉發操作。

確實比自己寫Java web來做轉發的好。

TODO 研究Nginx 配置檔案的語法

上面的編寫過程都是猜測出來的,沒有看官方文件。英語不好就是不願意看官網。後面有機會再研究具體語法。不過短期應該不會,很少用到nginx。到用到的時候再說吧。

TODO 正則表示式學習

雖然看了很多變正則表示式,但僅僅會寫一個簡單的基礎模型。nginx裡的配置讓我看到了正則表示式的強大。什麼時候深入學習一下呢?只能放到todo list裡了,短期沒時間規劃。

參考

瞭解到怎麼返回405:

照抄寫的跨域方案:

最先看到的解決方案,雖然不合適: