1.  问题描述《thinkphp实现短信验证注册》中,郝同学不止记录了短信验证码的实现方法,同时还记录了图片验证码的实现方法。
2.  分析通过问题描述,我们看出,问题出现在跨域上。那么,有两种可能,一种是因为跨域设置不正确;一种是因为thinkphp本身的问题。
采用另外一种跨域配置,问题依然存在。那就是thinkphp本身的问题了,经查找资料,问题定位在thinkphp的session跨域上。
3.  跨子域解决办法其实不管是ThinkPHP还是php本身,在解决session跨域问题的时候都需要设置session.cookie_domain。
1 ini_set( 'session.cookie_domain', ".domain.com" ) ;  
这时如果你开启了调试,那么可以用!但关闭了调试,就不管用了!
第二种情况:如果你目录下有.htaccess这个文件,那么你在根目录,index.php的第一行加入:
1 2 3 <?php  ini_set ('session.cookie_domain' ,".domain.com" );?> 
这种方法不管开不开启调试都管用!
然而,我们的问题并不是跨子域的问题,而是完全跨域,所以上述方法无效。
4.  完全跨域解决办法4.1.  获取图片验证码请求查看获取图片验证码的请求信息,Request Headers为:
1 2 3 4 5 6 7 8 Accept :image/webp,image/*,*/*;q=0 .8 Accept -Encoding:gzip, deflate, sdchAccept -Language:zh-CN,zh;q=0 .8 ,en-US;q=0 .6 ,en;q=0 .4 Connection :keep-aliveCookie :pma_lang=zh_CN; pma_collation_connection=utf8_unicode_ci; pma_iv-1 =wnpO4gv0eQRW1AMHmGr2ww%3 D%3 D; pmaUser-1 =weZPqS0%2 BW7nzFUVHRdqcfA%3 D%3 DHost :api.voidking.comReferer :http://localhost/ajax/ajax.htmlUser -Agent:Mozilla/5 .0  (Windows NT 6 .3 ; Win64; x64) AppleWebKit/537 .36  (KHTML, like Gecko) Chrome/54 .0 .2840 .71  Safari/537 .36 
Response Headers为:
1 2 3 4 5 6 7 8 9 10 11 Access -Control-Allow -Origin:*Cache -Control:post-check=0 , pre-check=0 Cache -Control:private, max-age=0 , no-store, no-cache, must-revalidateConnection :keep-aliveContent -Type:image/pngDate :Sun, 27  Nov 2016  12 :10 :44  GMTExpires :Thu, 19  Nov 1981  08 :52 :00  GMTPragma :no-cacheServer :nginxSet -Cookie:PHPSESSID=721 t4sqanvsii550m1dk8gq1o3; path=/; domain=.voidking.comTransfer -Encoding:chunked
4.2.  验证验证码请求查看验证验证码的请求信息,Request Headers为:
1 2 3 4 5 6 7 8 9 10 Accept :application/json, text/javascript, */*; q=0 .01 Accept -Encoding:gzip, deflateAccept -Language:zh-CN,zh;q=0 .8 ,en-US;q=0 .6 ,en;q=0 .4 Connection :keep-aliveContent -Length:9 Content -Type:application/x-www-form-urlencoded; charset=UTF-8 Host :api.voidking.comOrigin :http://localhostReferer :http://localhost/ajax/ajax.htmlUser -Agent:Mozilla/5 .0  (Windows NT 6 .3 ; Win64; x64) AppleWebKit/537 .36  (KHTML, like Gecko) Chrome/54 .0 .2840 .71  Safari/537 .36 
Response Headers为:
1 2 3 4 5 6 7 8 9 10 11 12 Access -Control-Allow -Origin:*Cache -Control:no-store, no-cache, must-revalidate, post-check=0 , pre-check=0 Connection :keep-aliveContent -Encoding:gzipContent -Type:text/html; charset=UTF-8 Date :Sun, 27  Nov 2016  12 :13 :21  GMTExpires :Thu, 19  Nov 1981  08 :52 :00  GMTPragma :no-cacheServer :nginxSet -Cookie:PHPSESSID=149 t0hhs2icqaaemvp39onkgp4; path=/; domain=.voidking.comTransfer -Encoding:chunkedVary :Accept-Encoding
4.3.  再次获取图片验证码请求Request Headers为:
1 2 3 4 5 6 7 8 9 Accept :image/webp,image/*,*/*;q=0 .8 Accept -Encoding:gzip, deflate, sdchAccept -Language:zh-CN,zh;q=0 .8 ,en-US;q=0 .6 ,en;q=0 .4 Cache -Control:max-age=0 Connection :keep-aliveCookie :pma_lang=zh_CN; pma_collation_connection=utf8_unicode_ci; pma_iv-1 =wnpO4gv0eQRW1AMHmGr2ww%3 D%3 D; pmaUser-1 =weZPqS0%2 BW7nzFUVHRdqcfA%3 D%3 D; PHPSESSID=721 t4sqanvsii550m1dk8gq1o3Host :api.voidking.comReferer :http://localhost/ajax/ajax.htmlUser -Agent:Mozilla/5 .0  (Windows NT 6 .3 ; Win64; x64) AppleWebKit/537 .36  (KHTML, like Gecko) Chrome/54 .0 .2840 .71  Safari/537 .36 
Response Headers为:
1 2 3 4 5 6 7 8 9 10 Access -Control -Allow -Origin :* Cache -Control :private , max-age=0 , no-store, no-cache, must-revalidateCache -Control :post-check= 0 , pre-check=0 Connection :keep-alive Content -Type :image/png Date :Sun , 27  Nov  2016  13 : 26 : 21  GMT Expires :Thu , 19  Nov  1981  08: 52 : 00  GMT Pragma :no-cache Server :nginx Transfer -Encoding :chunked 
4.4.  三次请求比较
第一次获取图片验证码请求,Cookie中没有PHPSESSID,所以,返回信息中有Set-Cookie。第二次获取图片验证码请求,Cookie中含有PHPSESSID,所以,返回信息中没有了Set-Cookie。而且第一次请求返回信息Set-Cookie中的PHPSESSID,和第二次请求请求信息Cookie中的PHPSESSID是相同的。
而验证图片验证码的ajax请求,没有Cookie,自然也没有PHPSESSID,所以,返回信息中也有Set-Cookie。
可见,我们需要在前端做一些修改,使之发送请求时带着Cookie。
4.5.  前端jquery设置1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <!DOCTYPE html > <html  lang ="zh" > <head >     <meta  charset ="UTF-8" >      <title > jquery</title >  </head > <body >     <p >          <img  src ="http://api.voidking.com/owner-bd/index.php/Home/CheckCode/getPicCode"  alt ="" >          <input  type ="text"  id ="picCode" >          <input  type ="button"  id ="send"  value ="验证" >      </p >  <script  src ="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js" > </script > <script >     $(function (         $('#send' ).click (function (                          $.ajax ({                 url : 'http://api.voidking.com/owner-bd/index.php/Home/CheckCode/checkPicCode' ,                 type : 'POST' ,                 crossDomain : true ,                 xhrFields : {                     withCredentials : true                  },                 dataType : 'json' ,                 data : {code : $('#picCode' ).val ()},                 success : function (data ){                     console .log (data);                 },                 error : function (xhr ){                     console .log (xhr);                 }             });         });     }); </script > </body > </html > 
请求时报错如下:
1 A wildcard '*'  cannot be used in  the 'Access-Control-Allow-Origin'  header  when  the credentials flag is  true . Origin 'http://localhost'  is  therefore not  allowed access . The credentials mode of  an XMLHttpRequest is  controlled by  the withCredentials attribute . 
出现了跨域报错,可见后端也需要做一些修改,使之可以接收跨域Cookie。
4.6.  后端nginx设置1 2 add_header  Access-Control-Allow-Origin http://localhost;add_header  Access-Control-Allow-Credentials true ;
注意:
后端nginx设置后,jquery的ajax请求正常了,可以携带Cookie,后端正常接收数据并返回数据。
由于angular的ajax请求不同于jquery,所以,我们还需要研究一下angular怎么发送携带Cookie的跨域请求。
4.7.  前端angular设置1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <!DOCTYPE html > <html > <head >     <meta  charset ="utf-8" >      <title > angular</title >      <script  src ="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js" > </script >  </head > <body  ng-app ="myApp"  >     <p  ng-controller ="myCtrl" >          <img  src ="http://api.voidking.com/owner-bd/index.php/Home/CheckCode/getPicCode"  alt ="" >          <input  type ="text"  id ="picCode"  ng-model ="picCode" >          <input  type ="button"  ng-click ="send()"   value ="验证" >      </p >  <script >     var  app = angular.module ('myApp' , []);     app.controller ('myCtrl' , function ($scope, $http, $httpParamSerializer ) {         $scope.send  = function (             $http({                 method :'POST' ,                 url :'http://api.voidking.com/owner-bd/index.php/Home/CheckCode/checkPicCode' ,                 headers :{                     'Content-Type' :'application/x-www-form-urlencoded'                  },                 withCredentials : true ,                 dataType : 'json' ,                 data : $httpParamSerializer({code : $scope.picCode })             }).then (function  successCallback (response ) {                 console .log (response.data );                 $scope.username  = response.data .username ;             }, function  errorCallback (response ) {                 console .log (response.data );             });         }     }); </script > </body > </html > 
5.  nginx配置文件结合《thinkphp部署到nginx服务器》中nginx的配置,最终nginx配置配置文件nginx.conf文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 error_log   logs/error .log  error  ;pid  logs/nginx.pid;user   www;worker_processes   auto;worker_rlimit_nofile  51200 ;events  {    use  epoll ;     worker_connections   51200 ; } http  {    client_body_buffer_size  32k ;     client_header_buffer_size  2k ;     client_max_body_size  2m ;     default_type  application/octet-stream;     log_not_found  off ;     server_tokens  off ;     include        mime.types;     gzip  on ;     gzip_min_length   1k ;     gzip_buffers      4  16k ;     gzip_http_version  1 .0 ;     gzip_comp_level  2 ;     gzip_types        text/plain text/css text/xml text/javascript application/x-javascript application/xml application/rss+xml application/xhtml+xml application/atom_xml;     gzip_vary  on ;          log_format   access  '$remote_addr  - $remote_user  [$time_local ] "$request " '                '$status  $body_bytes_sent  "$http_referer " '                '"$http_user_agent " $http_x_forwarded_for ' ;     server  {         listen  80  default_server;         server_name  localhost api.voidking.com;         root  /home/wwwroot/;         index  index.php index.html index.htm;              add_header  Access-Control-Allow-Origin http://localhost;         add_header  Access-Control-Allow-Credentials true ;         location  ~ \.php  {         root  /home/wwwroot/;             fastcgi_pass    127.0.0.1:9000 ;             fastcgi_index   index.php;         fastcgi_split_path_info  ^(.+\.php)(.*)$ ;             fastcgi_param  PATH_INFO $fastcgi_path_info ;             fastcgi_param   SCRIPT_FILENAME  $document_root $fastcgi_script_name ;             fastcgi_param   PHP_VALUE        open_basedir=$document_root :/tmp/:/proc/;             include         fastcgi_params;         }     }     include  vhost/*.conf ;      } 
6.  后记至此,大功告成,session跨域问题完美解决。
7.  书签