django复习 以及源码

django请求生命周期

在浏览器上输入网址会发生什么事?
(地址会朝我对应的ip地址发送get请求,get请求遵循http协议)
先进入实现了wsgi协议的web服务器----》进入django---》中间件---》路由---》视图---》取模板,取数据,用数据渲染模板---》返回模板的字符串---》在浏览器上看到页面了
1 wsgi和cgi:通用网关协议
# 实现了wsgi协议的web服务器:uwsgi
# 对应到java中就是tomcat

最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。

如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口协议来实现这样的服务器软件,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。而wsgiref模块就是python基于wsgi协议开发的服务模块。

 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里的数据点出来。

开发模式

#  开发模式(前后端分离和前后端不分离)
# -前后端不分离项目(后端渲染页面)
# -前后端分离项目
# -前端和后端通过json格式数据交互(不需要写模板语言)请求页面用ajax发请求,前后端只做json数据的交互,json数据拿回来的时候就用dom来渲染我的页面,前端拿到数据,页面前端自己渲染
前端可以是前端,后台,移动端和微信小程序
https://www.cnblogs.com/liuqingzheng/p/10900502.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的格式

-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,所以,搜索搜索引擎认为新的网址是暂时的。

  而301重定向是永久的重定向,搜索引擎在抓取新的内容的同时也将旧的网址替换为了重定向之后的网址

定义如下:

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;
}

 跨域

一、为什么会出现跨域问题
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)

二、什么是跨域
当一个请求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)
三、非同源限制
【1】无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB

【2】无法接触非同源网页的 DOM

【3】无法向非同源地址发送 AJAX 请求

四、跨域解决方法
【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:*")
原文地址:https://www.cnblogs.com/huangxuanya/p/11121222.html