在寫完 一個後端的前端學習之旅——1.決定學什麼 後我決定用coffeescript來看一些js框架,原本想用react,結果發現用它跟gulp配起來略煩,選來選去選擇了小半天決定最終用 spinejs, 看起來比較小,並且源碼有coffee和js兩個版本,還方便看,固然我知道這不是什麼主流框架,可能文檔什麼的少一些,但這樣更能夠看出看源碼的重要性,不管是否是python。前端
首先腳手架的項目就丟到一邊,基於腳手架建了一個項目 leaning-frontend, 因爲我把bower,npm的安裝文件放到git中管理,項目比較大,github傳輸太慢了,先放着開源中國的git上。python
而後bower裝了下spine,npm裝了下spine,我知道bower裝的東西會被gulp編譯到vendor.js裏面,然而貌似我不用npm裝spine的話在coffee裏面會require報錯(我暫時沒有管require到底幹毛的,看起來是import),bower裝的spine有個問題,由於gulp中採用了一個main-bower-file仍是什麼東西的找包的主文件,而後gulp講這個文件粘貼到vendor.js裏面,可是看起來spine是模塊分離的,須要單獨引用(或者是其餘什麼緣由),它並無bower.json。因此我修改了下gulp中的tasks/bower.coffee將全部的外部庫丟到一個文件夾裏面這樣能夠直接引用(有沒有更好的方案以後再說)。react
spine是mvc的,然而都是js,因此我在source下面建了controllers、models、views這三個文件夾,views裏面採用eco這麼種東西,看起來很像djang的模板。nginx
文檔git
class Contact extends Spine.Model @configure "Contact", "name" @extend Spine.Model.Ajax @url: "/users class App extends Spine.Controller constructor: -> super # Instantiate other controllers.. Photo.fetch()
根據這個文檔我知道了繼承Model後@extend一個Spine.Model.Ajax
而後添加一個url就能夠調用Model.fetch()了,so我在main.coffee裏面試了一下而後就出了些事情,容我慢慢道來。github
我準備用學堂在線的某些api作一些事情: http://www.xuetangx.com/api/v2/courses,下面是個人Model。web
class Course extends Spine.Model @configure "Course", "name" @extend Spine.Model.Ajax @url: "/api/v2/courses" module.exports = Course
fecth調用的時候首先404了,由於gulp在dev時啓動的是一個localhost的本地服務器(改爲0.0.0.0:3000了), spine在請求的時候url是相對路徑因此拼上的,好的吧,那我寫絕對路徑 @url: http://www.xuetangx.com/api/v2/courses
, 然而他依然是拼接的(http://192.168.9.191:3000/http://www.xue...),我丟你老母。面試
而後繼續看文檔發現了 Spine.Model.host = "http://my-endpoint"
,強行把host設走,我就在main.coffee第一行把host設置了學堂在線的host,而後 就跨域了。ajax
首先咱們知道,跨域是瀏覽器的某種安全限制,服務器端發起request並不存在跨域問題(這也是你能夠愉快的用腳本requests.get或者寫爬蟲的緣由)。
解決跨域問題有不少方案:chrome
若是外域原本就是你的,而且你以爲容許全部人訪問的話(通常不用,出發你就是一個專門的api服務器),nginx配上三行代碼便可(一搜就有)
同1,只是否是nginx上加,而是在代碼裏面作一些事情,例如django,用django-cors-headers
chrome能夠關閉跨域 啓動的時候加上一個參數便可C:\Users\Administrator\AppData\Local\Google\Chrome\Application\chrome.exe --disable-web-security
寫一個proxy,這樣你就有了1 2兩點的條件隨便搞
我選擇的是4+2
根據上面的方案選擇我在項目根目錄用django建了一個simple_server
cd 你的項目位置/leaning-frontend/simple_server pip install -r requirements.txt # 若是你懂python請用virtualenv什麼的 ./manage.py runserver 0.0.0.0:12345 # 12345是你想運行的端口號
urls.py, 只有一個url全部的請求都用CrossDomainAjaxView來處理
url(r'^(?P<request_url>.*)$', CrossDomainAjaxView.as_view(), name='ajax-hanler')
views.py, 這個view是作這麼一件事情的,將請求的url經過requests這個三方庫在個人服務器端請求外域服務器,而後講response轉變成django的response來返回給前端,暫時只寫了get(非get django要穿csrf什麼的比較煩)。這裏有件事情想講一下:
請求的header,我原本是想把接受到的全部header丟給requests的然而獲取不到數據,暫時無論;
response的header,我原本也是想把全部的response header都帶回來的,然而並不行,python級別的東西報了一個http 1.1有關的異常is_hop_by_hop,因此我也暫時沒帶過來。
rest framework僅僅是我想用他的view支持下非get post請求(然而我並沒作具體處理,實際上沒有任何做用)
# -*- coding: utf-8 -*- #from rest_framework.views import View #from rest_framework.generics import GenericAPIView as View from django.views.generic import View from django.conf import settings from simple_server.utils import get_request_header, get_request_headers from urlparse import urljoin from django.http.response import HttpResponse from wsgiref.util import is_hop_by_hop import requests class CrossDomainAjaxView(View): def transform_request_data(self, request, request_url): cross_domain_host = get_request_header(request, 'cross_domain_host') or settings.CROSS_DOMAIN_HOST url = urljoin(cross_domain_host, request_url) headers = get_request_headers(request) data = dict(request.GET) data.update(dict(request.POST)) request_data = { 'cross_domain_host': cross_domain_host, 'url': url, 'data': data, 'headers': headers, } return request_data def transform_response(self, requests_response): response = HttpResponse(requests_response.content, content_type= requests_response.headers.get('Content-Type', 'text/plain')) return response def get(self, request, request_url): request_data = self.transform_request_data(request, request_url) response = requests.get(request_data['url'], request_data['data']) #headers=request_data['headers']) print response.content return self.transform_response(response)
settings.py
middleware加上這兩個來容許跨域'corsheaders.middleware.CorsMiddleware'
、CORS_ORIGIN_ALLOW_ALL = True
, 而後因爲前端傳的是相對路徑因此我加了一個host CROSS_DOMAIN_HOST = 'http://www.xuetangx.com'
, get的時候支持在header裏面改變不一樣的host支持不一樣網站的api調用而不是寫死一個。
chrome的Network的XHR裏面此次看到請求了,哇哈哈攔路虎解決。
oh對了,順便fix了一些gulp對於spine須要支持的東西,主要是eco。
btw,發現學堂在線一個交互作的不錯的頁面 (好吧實際上是產品強行讓我貼的友鏈,各位隨意)
nginx能夠添加location來直接經過反向代理跨域
location /xuetangx { rewrite ^.+xuetangx/?(.*)$ /$1 break; include uwsgi_params; proxy_pass http://www.xuetangx.com/; } location /videoid2source/ { #include uwsgi_params; proxy_pass http://www.xuetangx.com/videoid2source/; }