django複習 以及源碼

django請求生命週期

在瀏覽器上輸入網址會發生什麼事?
(地址會朝我對應的ip地址發送get請求,get請求遵循http協議)
先進入實現了wsgi協議的web服務器----》進入django---》中間件---》路由---》視圖---》取模板,取數據,用數據渲染模板---》返回模板的字符串---》在瀏覽器上看到頁面了
1 wsgi和cgi:通用網關協議
# 實現了wsgi協議的web服務器:uwsgi
# 對應到java中就是tomcat

最簡單的Web應用就是先把HTML用文件保存好,用一個現成的HTTP服務器軟件,接收用戶請求,從文件中讀取HTML,返回。javascript

若是要動態生成HTML,就須要把上述步驟本身來實現。不過,接受HTTP請求、解析HTTP請求、發送HTTP響應都是苦力活,若是咱們本身來寫這些底層代碼,還沒開始寫動態HTML呢,就得花個把月去讀HTTP規範。php

正確的作法是底層代碼由專門的服務器軟件實現,咱們用Python專一於生成HTML文檔。由於咱們不但願接觸到TCP鏈接、HTTP原始請求和響應格式,因此,須要一個統一的接口協議來實現這樣的服務器軟件,讓咱們專心用Python編寫Web業務。這個接口就是WSGI:Web Server Gateway Interface。而wsgiref模塊就是python基於wsgi協議開發的服務模塊。html

 1 from wsgiref.simple_server import make_server
 2 
 3 def mya(environ, start_response):
 4     print(environ)
 5     start_response('200 OK', [('Content-Type', 'text/html')])
 6     if environ.get('PATH_INFO') == '/index':
 7         with open('index.html','rb') as f:
 8             data=f.read()
 9 
10     elif environ.get('PATH_INFO') == '/login':
11         with open('login.html', 'rb') as f:
12             data = f.read()
13     else:
14         data=b'<h1>Hello, web!</h1>'
15     return [data]
16 
17 if __name__ == '__main__':
18     myserver = make_server('', 8011, mya)
19     print('監聽8010')
20     myserver.serve_forever()

整個django框架就至關於def mya這個函數,只不過diango不是用函數,是用類包裝起來。前端

對象加()調用是__call__的方法,__call__裏面有這兩個參數(environ, start_response),只要遵循這個http協議就會有這兩個參數。wsgi就是將http請求拆開了,拆成python當中可以識別的變量,http直接來,能讀出來就是字符串,可是還要作相應的處理,因此協議規定按照什麼格式拆,拆到哪裏,就是將數據當成字典拆到environ裏面去,無論請求方式,請求頭部等等而後再傳到後面的可調用對象裏面去,而後django就把這個東西包裝成了對象request,因此request能夠點http裏的數據點出來。java

開發模式

#  開發模式(先後端分離和先後端不分離)
# -先後端不分離項目(後端渲染頁面)
# -先後端分離項目
# -前端和後端經過json格式數據交互(不須要寫模板語言)請求頁面用ajax發請求,先後端只作json數據的交互,json數據拿回來的時候就用dom來渲染個人頁面,前端拿到數據,頁面前端本身渲染
前端能夠是前端,後臺,移動端和微信小程序
http://www.javashuo.com/article/p-ppeoyntg-ek.html

cbv源碼分析

-FBV和CBV
# -執行流程:
# -路由若是這麼配置:url(r'^test/', views.Test.as_view()),
# 請求經過中間件後進入路由--->根據路由匹配,一旦成功,會執行後面函數(request)---》本質就是執行了as_view內部的view函數----》內部又調用了self.dispatch---->根據請求方式,執行不一樣的方法(必然get請求,就會執行咱麼寫的視圖類的get方法)
# -嘗試本身封裝一個APIView,重寫dispatch方法,在執行父類的dispatch以前,寫一些邏輯,請求來了,就會執行這些邏輯
url()其實就是一個函數,views.Test.as_view()就是函數地址加括號,而且把request傳進去,
#  python中一切皆對象
# def test():
# print('xxxx')
# test.name='lqz'
# print(test.name)

restful規範(importment,interview)

一 什麼是RESTful

  • REST與技術無關,表明的是一種軟件架構風格,REST是Representational State Transfer的簡稱,中文翻譯爲「表徵狀態轉移」
  • REST從資源的角度類審視整個網絡,它將分佈在網絡中某個節點的資源經過URL進行標識,客戶端應用經過URL來獲取資源的表徵,得到這些表徵導致這些應用轉變狀態
  • REST與技術無關,表明的是一種軟件架構風格,REST是Representational State Transfer的簡稱,中文翻譯爲「表徵狀態轉移」
  • 全部的數據,不過是經過網絡獲取的仍是操做(增刪改查)的數據,都是資源,將一切數據視爲資源是REST區別與其餘架構風格的最本質屬性
  • 對於REST這種面向資源的架構風格,有人提出一種全新的結構理念,即:面向資源架構(ROA:Resource Oriented Architecture)
  • 資源就是實實存在的東西,如從動物園中新增一頭動物,殺死一頭動物    -10條
#     -1 API與用戶的通訊協議,老是使用HTTPs協議。(http不安全,數據被截斷,數據就會所有展現出來)
# -2 域名有區分
      (dtl是模板語言,可使用python等進行模板渲染再返回給前端)
      (後臺管理並無作先後端分離,用的就是dtl,而不是前端渲染)
# -https://api.example.com   儘可能將API部署在專用域名(會存在跨域問題)
# -https://example.org/api/ 訪問api表明就是訪問路由接口
# -3 版本
      (就是如微博開一個接口,而後我寫一個app去訪問這個接口,須要傳入兩個參數,返回一個參數,而後後期微博數據須要改動,
       變成了一個接口須要傳入三個參數,返回兩個參數,不可能去改變個人app,只能再更新一個微博版本,開一個新的接口,
      而後app去鏈接一個新的接口,這期間就會有緩衝的過程)
# -能夠放在路徑中 URL 如:https://api.example.com/v1/
#        -能夠放在請求頭中  跨域時,引起發送屢次請求
# -4 路徑,視網絡上任何東西都是資源,均使用名詞表示(重點)
# -https://api.example.com/v1/zoos
# -5 經過method 區分是什麼操做
# -get表示獲取
# -post表示新增
# -delete表示刪除
# -patch/put 表示修改
# -6 過濾,經過在url上傳參的形式傳遞搜索條件
      
  • https://api.example.com/v1/zoos?limit=10:指定返回記錄的數量
  • https://api.example.com/v1/zoos?offset=10:指定返回記錄的開始位置
  • https://api.example.com/v1/zoos?page=2&per_page=100:指定第幾頁,以及每頁的記錄數
  • https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回結果按照哪一個屬性排序,以及排序順序
  • https://api.example.com/v1/zoos?animal_type_id=1:指定篩選條件

# -7 狀態碼
# {"status_code":100}
200 OK - [GET]:服務器成功返回用戶請求的數據,該操做是冪等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數據成功。
202 Accepted - [*]:表示一個請求已經進入後臺排隊(異步任務)
204 NO CONTENT - [DELETE]:用戶刪除數據成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發出的請求有錯誤,服務器沒有進行新建或修改數據的操做,該操做是冪等的。
401 Unauthorized - [*]:表示用戶沒有權限(令牌、用戶名、密碼錯誤)。
403 Forbidden - [*] 表示用戶獲得受權(與401錯誤相對),可是訪問是被禁止的。
404 NOT FOUND - [*]:用戶發出的請求針對的是不存在的記錄,服務器沒有進行操做,該操做是冪等的。
406 Not Acceptable - [GET]:用戶請求的格式不可得(好比用戶請求JSON格式,可是隻有XML格式)。
410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再獲得的。
422 Unprocesable entity - [POST/PUT/PATCH] 當建立一個對象時,發生一個驗證錯誤。
500 INTERNAL SERVER ERROR - [*]:服務器發生錯誤,用戶將沒法判斷髮出的請求是否成功。

更多看這裏:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

# -8 錯誤處理,應返回錯誤信息
# {"status_code":100,'msg':'登陸成功'}
# {"status_code":101,'msg':'用戶名錯誤'}
# -9 返回結果,針對不一樣操做,服務器向用戶返回的結果
# -get獲取全部資源/get獲取一個資源
# -127.0.0.1/api/vi/books 獲取全部圖書
# {"status_code":100,'msg':'獲取成功',data:[{},{}]}
# -127.0.0.1/api/vi/books/3 獲取id爲3的圖書
# {"status_code":100,'msg':'獲取成功',data:{name:xx,....}}
# -新增數據,把新增的數據再返回
# -修改了數據,返回完整的資源對象
# -刪除數據,返回一個空文檔
    • 錯誤處理,應返回錯誤信息,error當作key。
      1
      2
      3
      {
           error:  "Invalid API key"
      }
    • 返回結果,針對不一樣操做,服務器向用戶返回的結果應該符合如下規範。
      1
      2
      3
      4
      5
      6
      GET  / collection:返回資源對象的列表(數組)
      GET  / collection / resource:返回單個資源對象
      POST  / collection:返回新生成的資源對象
      PUT  / collection / resource:返回完整的資源對象
      PATCH  / collection / resource:返回完整的資源對象
      DELETE  / collection / resource:返回一個空文檔

#
# -10 返回結果中提供連接
Hypermedia API,RESTful API最好作到Hypermedia,即返回結果中提供連接,連向其餘API方法,使得用戶不查文檔,也知道下一步應該作什麼。
1
2
3
4
5
6
{ "link" : {
   "rel" :    "collection https://www.example.com/zoos" ,
   "href" :   "https://api.example.com/zoos" ,
   "title" "List of zoos" ,
   "type" :   "application/vnd.yourformat+json"
}}

django編寫restful接口

#  DG軟件
# -pycharm開發
# -idea
# -goland
# -AndroidStadio
不一樣程序能夠用同一個數據庫
views.py
from django.shortcuts import render
from django.http import JsonResponse
# Create your views here.
from app01 import models
def Book(request):
    #獲取全部的圖書
    if request.method == 'GET':
        books = models.Book.objects.all()
        #把queryset對象轉成json格式的字符串
        # li = []
        # for book in books:
        #     bo = {'name':book.name,'publish':book.publish}
        #     li.append(bo)
        #列表推導式
        li=[{'name':book.name,'publish':book.publish} for book in books ]

        response = {'code':100,'msg':'查詢成功','data':li}
        #safe=False 若是序列化的對象中有列表,須要設置
        return JsonResponse(response ,safe=False,json_dumps_params={'ensure_ascii':False})

models.py
from
django.db import models # Create your models here. class Book(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) publish = models.CharField(max_length=32)

 1    def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
 2                  json_dumps_params=None, **kwargs):
 3         if safe and not isinstance(data, dict):
 4             raise TypeError(
 5                 'In order to allow non-dict objects to be serialized set the '
 6                 'safe parameter to False.'
 7             )
 8         if json_dumps_params is None:
 9             json_dumps_params = {}
10         kwargs.setdefault('content_type', 'application/json')
11         data = json.dumps(data, cls=encoder, **json_dumps_params)
12         super(JsonResponse, self).__init__(content=data, **kwargs)
源碼

APIView源碼簡單分析

# 6 drf:APIView 的源碼,Requset的源碼
# -安裝:
# -pip3 install djangorestframework
# -pycharm中安裝
# -使用
# -第一步,再寫視圖,都寫cbv
# from rest_framework.views import APIView
# class Books(APIView):
# pass
# -在setting中配置
# INSTALLED_APPS= [
# 。。。。。
# 'rest_framework'
# ]
#
# -源碼分析:
# 繼承了APIView 以後:
# -1 全部的請求都沒有csrf的認證了
# -2 在APIView中as_view本質仍是調用了父類的as_view(View的as_view)
# -3 as_view中調用dispatch -----》這個dispatch是APIView的dispatch
    @classmethod
    def as_view(cls, **initkwargs):
        """
        Store the original class on the view function.

        This allows us to discover information about the view when we do URL
        reverse lookups.  Used for breadcrumb generation.
        """
        if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
            def force_evaluation():
                raise RuntimeError(
                    'Do not evaluate the `.queryset` attribute directly, '
                    'as the result will be cached and reused between requests. '
                    'Use `.all()` or call `.get_queryset()` instead.'
                )
            cls.queryset._fetch_all = force_evaluation

        view = super(APIView, cls).as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs

        # Note: session based authentication is explicitly CSRF validated,
        # all other authentication is CSRF exempt.
        return csrf_exempt(view)
源碼
def csrf_exempt(view_func):
    """
    Marks a view function as being exempt from the CSRF view protection.
    """
    # We could just do view_func.csrf_exempt = True, but decorators
    # are nicer if they don't have side-effects, so we return a new
    # function.
    def wrapped_view(*args, **kwargs):
        return view_func(*args, **kwargs)
    wrapped_view.csrf_exempt = True
    return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)
源碼
class View(object):
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in six.iteritems(kwargs):
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view
源碼

APIView的dispatch方法和request類分析

    -APIVIew的dispatch方法:
# -1 對原生request對象作了一層包裝(面向對象的封裝),之後再用的request對象都新的request對象
# -2 在APIView中self.initial(request, *args, **kwargs),裏面有頻率控制,權限控制和認證相關
# -3 根據請求方法執行我們寫的視圖類中的相應方法
# --視圖類中方法的request對象,已經變成了封裝後的request
# -Request類:
# -1 原生的request是self._request
# -2 取以post形式提交的數據,從request.data中取(urlencoded,formdata,json格式)
# -3 query_params 就是原生request的GET的數據
# -4 上傳的文件是從FILES中取
# -5 (重點)其餘的屬性,直接request.屬性名(由於重寫了__getattr__方法)

postman的安裝和使用

美化jason的格式python

-Django的請求生命週期
-CBV源碼分析
-類名.as_view()---->執行結果返回內存地址---》內存函數view的內存地址---》請求路徑跟路由匹配成,會調用view(request)
view()內部調用了self.disaptch---->根據請求不一樣,執行不一樣的方法

-restful規範:
-10
-1 路徑中資源都名詞,能夠用複數
-2 經過請求方式來執行不一樣操做
-3 返回狀態碼
-4 返回錯誤信息
-5 返回的數據中帶連接
-用原生django寫restful的接口
-drf
-使用:
-1 在setting.py 中把rest_framework加入到app中
-2 之後再寫全寫CBV,繼承APIView
-源碼分析:
-APIView:重寫了dispatch方法:1 包裝request 2 加入了一些校驗
-Request對象:重寫了__getattr__ query_params FILES request.data

 

 

圖書的增刪查改接口
# -登陸以後才能操做修改,新增,刪除接口
from django.db import models

# Create your models here.
class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField()
    # 閱讀數
    # reat_num=models.IntegerField(default=0)
    # 評論數
    # commit_num=models.IntegerField(default=0)

    publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
    authors=models.ManyToManyField(to='Author')
    def __str__(self):
        return self.name


class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE)


class AuthorDatail(models.Model):
    nid = models.AutoField(primary_key=True)
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    addr = models.CharField(max_length=64)


class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()
models.py
from rest_framework import serializers
from app01 import models
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model=models.Book
        fields='__all__'
        # depth=1
myserializer.py
from django.shortcuts import render

# Create your views here.
class Get():
    def get(self,request,*args,**kwargs):
        response = {'code': 100, 'msg': '查詢成功'}
        ret=self.models_object
        book_ser=self.ser(instance=ret,many=True)
        response['data']=book_ser.data
        return Response(response)

from app01 import models
from app01.MySer import BookSerializer
from rest_framework.views import  APIView
from rest_framework.response import  Response
class Books(APIView,Get):
    models_object=models.Book.objects.all()
    ser=BookSerializer

    def post(self,request,*args,**kwargs):
        print(request.data)
        print(type(request.data))
        response={'code': 100, 'msg': '新增成功'}
        book_ser=BookSerializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
        else:
            response['code']=101
            response['msg']=book_ser.errors

        return Response(response)

class BookDetail(APIView):
    def get(self,request,id):
        response = {'code': 100, 'msg': '查詢成功'}
        ret=models.Book.objects.filter(pk=id).first()
        book_ser=BookSerializer(instance=ret,many=False)
        response['data']=book_ser.data
        return Response(response)
    def put(self,request,id):
        response = {'code': 100, 'msg': '修改爲功'}
        ret=models.Book.objects.filter(pk=id).first()
        book_ser=BookSerializer(instance=ret,data=request.data)
        if book_ser.is_valid():
            book_ser.save()
        else:
            response['code'] = 101
            response['msg'] = book_ser.errors
        return Response(response)

    def delete(self, request, id):
        response = {'code': 100, 'msg': '刪除成功'}
        models.Book.objects.filter(pk=id).delete()

        return Response(response)


class Publish(APIView,Get):
    models_object=models.Publish.objects.all()
    ser=BookSerializer
views.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^books/$', views.Books.as_view()),
    url(r'^books/(?P<id>\d+)$', views.BookDetail.as_view()),

]
urls.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework'
]
settings.py
301和302的區別

302重定向只是暫時的重定向,搜索引擎會抓取新的內容而保留舊的地址,由於服務器返回302,因此,搜索搜索引擎認爲新的網址是暫時的。git

  而301重定向是永久的重定向,搜索引擎在抓取新的內容的同時也將舊的網址替換爲了重定向以後的網址web

 

定義以下:ajax

301 Moved Permanently 被請求的資源已永久移動到新位置,而且未來任何對此資源的引用都應該使用本響應返回的若干個URI之一。若是可能,擁有連接編輯功能的客戶端應當自動把請求的地址修改成從服務器反饋回來的地址。除非額外指定,不然這個響應也是可緩存的。數據庫


302 Found 請求的資源如今臨時從不一樣的URI響應請求。因爲這樣的重定向是臨時的,客戶端應當繼續向原有地址發送之後的請求。只有在Cache-Control或Expires中進行了指定的狀況下,這個響應纔是可緩存的。

字面上的區別就是301是永久重定向,而302是臨時重定向。 固然,他們之間也是有共同點的,就是用戶均可以看到url替換爲了一個新的,而後發出請求。

 

 

301適合永久重定向

  301比較經常使用的場景是使用域名跳轉。

  好比,咱們訪問 http://www.baidu.com 會跳轉到 https://www.baidu.com,發送請求以後,就會返回301狀態碼,而後返回一個location,提示新的地址,瀏覽器就會拿着這個新的地址去訪問。 

  注意: 301請求是能夠緩存的, 即經過看status code,能夠發現後面寫着from cache。

     或者你把你的網頁的名稱從php修改成了html,這個過程當中,也會發生永久重定向。

 

 

302用來作臨時跳轉

  好比未登錄的用戶訪問用戶中心重定向到登陸頁面。

  訪問404頁面會從新定向到首頁。 

##niginx 301/302配置

rewrite後面接上permenent就表明301跳

//把來自veryyoung.me的請求301跳到 www.veryyoung.me
if ($host != 'veryyoung.me') {
    rewrite ^/(.*)$ http://www.veryyoung.me/$1 permanent;
}

 

接上redirect就表明302跳

//把來自veryyoung.me的請求302跳到 www.veryyoung.me
if ($host != 'veryyoung.me') {
    rewrite ^/(.*)$ http://www.veryyoung.me/$1 redirect;
}

 跨域

1、爲何會出現跨域問題
出於瀏覽器的同源策略限制。同源策略(Sameoriginpolicy)是一種約定,它是瀏覽器最核心也最基本的安全功能,若是缺乏了同源策略,則瀏覽器的正常功能可能都會受到影響。能夠說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。同源策略會阻止一個域的javascript腳本和另一個域的內容進行交互。所謂同源(即指在同一個域)就是兩個頁面具備相同的協議(protocol),主機(host)和端口號(port)

2、什麼是跨域
當一個請求url的協議、域名、端口三者之間任意一個與當前頁面url不一樣即爲跨域

當前頁面url                                  被請求頁面url                                  是否跨域          緣由
http://www.test.com/                    http://www.test.com/index.html        否                     同源(協議、域名、端口號相同)
http://www.test.com/                    https://www.test.com/index.html      跨域                  協議不一樣(http/https)
http://www.test.com/                    http://www.baidu.com/                     跨域                  主域名不一樣(test/baidu)
http://www.test.com/                    http://blog.test.com/                         跨域                  子域名不一樣(www/blog)
http://www.test.com:8080/           http://www.test.com:7001/               跨域                  端口號不一樣(8080/7001)
3、非同源限制
【1】沒法讀取非同源網頁的 Cookie、LocalStorage 和 IndexedDB

【2】沒法接觸非同源網頁的 DOM

【3】沒法向非同源地址發送 AJAX 請求

4、跨域解決方法
【1】設置document.domain解決沒法讀取非同源網頁的 Cookie問題

由於瀏覽器是經過document.domain屬性來檢查兩個頁面是否同源,所以只要經過設置相同的document.domain,兩個頁面就能夠共享Cookie

// 兩個頁面都設置
document.domain = 'test.com';

【2】跨文檔通訊 API:window.postMessage()

調用postMessage方法實現父窗口http://test1.com向子窗口http://test2.com發消息(子窗口一樣能夠經過該方法發送消息給父窗口)

// 父窗口打開一個子窗口
var openWindow = window.open('http://test2.com', 'title');

// 父窗口向子窗口發消息(第一個參數表明發送的內容,第二個參數表明接收消息窗口的url)
openWindow.postMessage('Nice to meet you!', 'http://test2.com');

調用message事件,監聽對方發送的消息

// 監聽 message 消息
window.addEventListener('message', function (e) {
console.log(e.source); // e.source 發送消息的窗口
console.log(e.origin); // e.origin 消息發向的網址
console.log(e.data); // e.data 發送的消息
},false);

【3】JSONP

JSONP 是服務器與客戶端跨源通訊的經常使用方法。最大特色就是簡單適用,兼容性好(兼容低版本IE),缺點是隻支持get請求,不支持post請求。

核心思想:網頁經過添加一個<script>元素,向服務器請求 JSON 數據,服務器收到請求後,將數據放在一個指定名字的回調函數的參數位置傳回來。

<script src="http://test.com/data.php?callback=dosomething"></script>
// 向服務器test.com發出請求,該請求的查詢字符串有一個callback參數,用來指定回調函數的名字

// 處理服務器返回回調函數的數據
<script type="text/javascript">
function dosomething(data){
//處理得到的數據
}
</script>

【4】CORS

CORS 是跨域資源分享(Cross-Origin Resource Sharing)的縮寫。它是 W3C 標準,屬於跨源 AJAX 請求的根本解決方法。

1.前端代碼(須要判斷瀏覽器是否支持狀況)

function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {

// 此時即支持CORS的狀況
// 檢查XMLHttpRequest對象是否有「withCredentials」屬性
// 「withCredentials」僅存在於XMLHTTPRequest2對象裏
xhr.open(method, url, true);

} else if (typeof!= "undefined") {

// 不然檢查是否支持XDomainRequest,IE8和IE9支持
// XDomainRequest僅存在於IE中,是IE用於支持CORS請求的方式
xhr = new XDomainRequest();
xhr.open(method, url);

} else {

// 不然,瀏覽器不支持CORS
xhr = null;

}
return xhr;
}

var xhr = createCORSRequest('GET', url);
if (!xhr) {
throw new Error('CORS not supported');
}

 


2.服務器

服務器端對於CORS的支持,主要是經過設置Access-Control-Allow-Origin來進行的。若是瀏覽器檢測到相應的設置,就能夠容許Ajax進行跨域的訪問。咱們主要介紹Apache和PHP裏的設置方法

Apache須要使用mod_headers模塊來激活HTTP頭的設置,它默認是激活的。你只須要在Apache配置文件的<Directory>, <Location>, <Files>或<VirtualHost>的配置里加入如下內容便可

Header set Access-Control-Allow-Origin *

 

PHP使用以下代碼設置便可

<?php
header("Access-Control-Allow-Origin:*")
相關文章
相關標籤/搜索